def normaliseContinuum(spec): """ Based on example.py normalize_whole_spectrum_strategy1_ignoring_prefixed_strong_lines function """ model = 'Splines' degree = 2 nknots = None from_resolution = INSTRUMENT[args.instrument]['RESOLUTION'] # continuum fit order = 'median+max' median_wave_range = 0.01 max_wave_range = 1.0 strong_lines = ispec.read_line_regions(strongLines) continuum_model = ispec.fit_continuum(spec, \ from_resolution=from_resolution, \ nknots=nknots, \ degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, \ order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) # continuum normalisation spec_norm = ispec.normalize_spectrum(spec, \ continuum_model, \ consider_continuum_errors=False) return spec_norm
def normalize_whole_spectrum(spec_id, med_wave, max_wave): """ Use the whole spectrum, strategy 'median+max' """ star_spectrum = ispec.read_spectrum(spec_id) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = 47000 # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order='median+max' median_wave_range=med_wave max_wave_range=max_wave star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Continuum normalization --------------------------------------------------- logging.info("Continuum normalization...") normalized_star_spectrum = ispec.normalize_spectrum(star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") ispec.write_spectrum(normalized_star_spectrum, spec_id)
def test_normalize_spectrum_in_segments(self): """ Fit continuum in each segment independently, strategy 'median+max' """ star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = 1 from_resolution = 80000 # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 segments = ispec.read_segment_regions( ispec_dir + "/input/regions/fe_lines_segments.txt") star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ independent_regions=segments, nknots=nknots, degree=degree,\ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Continuum normalization --------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") np.testing.assert_equal(star_spectrum['waveobs'], normalized_star_spectrum['waveobs']) self.assertAlmostEqual(star_spectrum['flux'][0], 0.67077) self.assertAlmostEqual(star_spectrum['flux'][-1], 2.2169) self.assertAlmostEqual(star_spectrum['err'][0], 0.0021259) self.assertAlmostEqual(star_spectrum['err'][-1], 0.0043878) self.assertAlmostEqual(normalized_star_spectrum['flux'][0], 1.0) self.assertAlmostEqual(normalized_star_spectrum['flux'][-1], 1.0) self.assertAlmostEqual(normalized_star_spectrum['err'][0], 0.0) self.assertAlmostEqual(normalized_star_spectrum['err'][-1], 0.0) self.assertAlmostEqual(normalized_star_spectrum['flux'][11], 0.9928764307623508) self.assertAlmostEqual(normalized_star_spectrum['flux'][58288], 0.960387654522309) self.assertAlmostEqual(normalized_star_spectrum['err'][11], 0.0028468129511384785) self.assertAlmostEqual(normalized_star_spectrum['err'][58288], 0.0019771951824093786) self.assertEqual( len(np.where(normalized_star_spectrum['flux'] != 1.)[0]), 33722) self.assertTrue( np.all(star_continuum_model(star_spectrum['waveobs']) == 1))
def test_normalize_spectrum_using_continuum_regions(self): """ Consider only continuum regions for the fit, strategy 'median+max' """ star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = 80000 # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 continuum_regions = ispec.read_continuum_regions( ispec_dir + "/input/regions/fe_lines_continuum.txt") star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ continuum_regions=continuum_regions, nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Continuum normalization --------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") np.testing.assert_equal(star_spectrum['waveobs'], normalized_star_spectrum['waveobs']) self.assertAlmostEqual(star_spectrum['flux'][0], 0.67077) self.assertAlmostEqual(star_spectrum['flux'][-1], 2.2169) self.assertAlmostEqual(star_spectrum['err'][0], 0.0021259) self.assertAlmostEqual(star_spectrum['err'][-1], 0.0043878) self.assertAlmostEqual(normalized_star_spectrum['flux'][0], 0.7990890725070141) self.assertAlmostEqual(normalized_star_spectrum['flux'][-1], 0.9887281323707806) self.assertAlmostEqual(normalized_star_spectrum['err'][0], 0.0025325871151701197) self.assertAlmostEqual(normalized_star_spectrum['err'][-1], 0.001956940457042046) self.assertTrue( np.all(star_continuum_model(star_spectrum['waveobs']) == 1))
def test_normalize_whole_spectrum_ignoring_prefixed_strong_lines(self): """ Use the whole spectrum but ignoring some strong lines, strategy 'median+max' """ star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = 80000 # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 strong_lines = ispec.read_line_regions( ispec_dir + "/input/regions/strong_lines/absorption_lines.txt") star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ ignore=strong_lines, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Continuum normalization --------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") np.testing.assert_equal(star_spectrum['waveobs'], normalized_star_spectrum['waveobs']) self.assertAlmostEqual(star_spectrum['flux'][0], 0.67077) self.assertAlmostEqual(star_spectrum['flux'][-1], 2.2169) self.assertAlmostEqual(star_spectrum['err'][0], 0.0021259) self.assertAlmostEqual(star_spectrum['err'][-1], 0.0043878) self.assertAlmostEqual(normalized_star_spectrum['flux'][0], 0.8005567874185445) self.assertAlmostEqual(normalized_star_spectrum['flux'][-1], 0.9874528805693361) self.assertAlmostEqual(normalized_star_spectrum['err'][0], 0.0025372388067043607) self.assertAlmostEqual(normalized_star_spectrum['err'][-1], 0.0019544164145257493) self.assertTrue( np.all(star_continuum_model(star_spectrum['waveobs']) == 1))
def test_normalize_whole_spectrum(self): """ Use the whole spectrum, strategy 'median+max' """ star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = 80000 # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Continuum normalization --------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") np.testing.assert_equal(star_spectrum['waveobs'], normalized_star_spectrum['waveobs']) self.assertAlmostEqual(star_spectrum['flux'][0], 0.67077) self.assertAlmostEqual(star_spectrum['flux'][-1], 2.2169) self.assertAlmostEqual(star_spectrum['err'][0], 0.0021259) self.assertAlmostEqual(star_spectrum['err'][-1], 0.0043878) self.assertAlmostEqual(normalized_star_spectrum['flux'][0], 0.8052457389161867) self.assertAlmostEqual(normalized_star_spectrum['flux'][-1], 0.9895767577073404) self.assertAlmostEqual(normalized_star_spectrum['err'][0], 0.0025520997008839415) self.assertAlmostEqual(normalized_star_spectrum['err'][-1], 0.0019586200989978207) self.assertTrue( np.all(star_continuum_model(star_spectrum['waveobs']) == 1))
def test_normalize_whole_spectrum_with_template(self): """ Use a template to normalize the whole spectrum """ star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") synth_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") #--- Continuum fit ------------------------------------------------------------- model = "Template" nknots = None # Automatic: 1 spline every 5 nm (in this case, used to apply a gaussian filter) from_resolution = 80000 median_wave_range = 5.0 #strong_lines = ispec.read_line_regions(ispec_dir + "/input/regions/strong_lines/absorption_lines.txt") strong_lines = ispec.read_line_regions( ispec_dir + "/input/regions/relevant/relevant_line_masks.txt") #strong_lines = None star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ ignore=strong_lines, \ nknots=nknots, \ median_wave_range=median_wave_range, \ model=model, \ template=synth_spectrum) #--- Continuum normalization --------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") np.testing.assert_equal(star_spectrum['waveobs'], normalized_star_spectrum['waveobs']) self.assertAlmostEqual(star_spectrum['flux'][0], 0.67077) self.assertAlmostEqual(star_spectrum['flux'][-1], 2.2169) self.assertAlmostEqual(star_spectrum['err'][0], 0.0021259) self.assertAlmostEqual(star_spectrum['err'][-1], 0.0043878) self.assertAlmostEqual(normalized_star_spectrum['flux'][0], 0.7964201448878107) self.assertAlmostEqual(normalized_star_spectrum['flux'][-1], 0.997168332612696) self.assertAlmostEqual(normalized_star_spectrum['err'][0], 0.002524128368914824) self.assertAlmostEqual(normalized_star_spectrum['err'][-1], 0.0019736457259407225) self.assertTrue( np.all(star_continuum_model(star_spectrum['waveobs']) == 1))
def normalize_spectrum(star_spectrum, res=80000, model="Splines", degree=2, nknots=None): ''' Fit continuum ignoring strong lines and using fe lines template, strategy 'median+max' #### #### ASSUMING DEFAULT VALUES FOR: #### RESOLUTION, MODEL FOR CONTINUUM, DEGREE OF MODEL, NKNOTS!!!! #### TAKE CARE!!!! #### returns normalized star spectrum object and continumm model ''' from_resolution = res #define resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 # read continuum regions from Fe lines and strong lines continuum_regions = ispec.read_continuum_regions(\ ispec_dir + "/input/regions/fe_lines_continuum.txt") strong_lines = ispec.read_line_regions(\ ispec_dir + "/input/regions/strong_lines/absorption_lines.txt") star_continuum_model = ispec.fit_continuum(star_spectrum,\ from_resolution=from_resolution, ignore=strong_lines,\ continuum_regions=continuum_regions, nknots=nknots, degree=degree,\ median_wave_range=median_wave_range, max_wave_range=max_wave_range,\ model=model, order=order, automatic_strong_line_detection=True,\ strong_line_probability=0.5, use_errors_for_fitting=True) #--- Continuum normalization ----------------------------------------------- logging.info("Continuum normalization...") normalized_star_spectrum = ispec.normalize_spectrum(star_spectrum,\ star_continuum_model, consider_continuum_errors=False) #Use a fixed value because the spectrum is already normalized #you need continuum model to be able to synt or interpolate params from grid star_continuum_model = ispec.fit_continuum(star_spectrum, \ fixed_value=1.0, model="Fixed value") return normalized_star_spectrum, star_continuum_model
def test_determine_astrophysical_parameters_using_synth_spectra(self): code = "spectrum" star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #--- Model spectra ---------------------------------------------------------- # Parameters initial_teff = 5750.0 initial_logg = 4.5 initial_MH = 0.00 initial_alpha = ispec.determine_abundance_enchancements(initial_MH) initial_vmic = ispec.estimate_vmic(initial_teff, initial_logg, initial_MH) initial_vmac = ispec.estimate_vmac(initial_teff, initial_logg, initial_MH) initial_vsini = 2.0 initial_limb_darkening_coeff = 0.6 initial_R = to_resolution initial_vrad = 0 max_iterations = 6 # Selected model amtosphere, linelist and solar abundances #model = ispec_dir + "/input/atmospheres/MARCS/" model = ispec_dir + "/input/atmospheres/MARCS.GES/" #model = ispec_dir + "/input/atmospheres/MARCS.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Castelli/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kurucz/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kirby/" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.300_1100nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.1100_2400nm/atomic_lines.tsv" atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_hfs_iso.420_920nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_nohfs_noiso.420_920nm/atomic_lines.tsv" if "ATLAS" in model: solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.1998/stdatom.dat" else: # MARCS solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.2007/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2005/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2009/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Anders.1989/stdatom.dat" isotope_file = ispec_dir + "/input/isotopes/SPECTRUM.lst" # Load chemical information and linelist atomic_linelist = ispec.read_atomic_linelist( atomic_linelist_file, wave_base=np.min(star_spectrum['waveobs']), wave_top=np.max(star_spectrum['waveobs'])) atomic_linelist = atomic_linelist[ atomic_linelist['theoretical_depth'] >= 0.01] # Select lines that have some minimal contribution in the sun isotopes = ispec.read_isotope_data(isotope_file) # Load model atmospheres modeled_layers_pack = ispec.load_modeled_layers_pack(model) # Load SPECTRUM abundances solar_abundances = ispec.read_solar_abundances(solar_abundances_file) # Free parameters #free_params = ["teff", "logg", "MH", "vmic", "vmac", "vsini", "R", "vrad", "limb_darkening_coeff"] free_params = ["teff", "logg", "MH", "vmic", "R"] # Free individual element abundance free_abundances = None linelist_free_loggf = None # Line regions line_regions = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all.txt".format( code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all_extended.txt".format(code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all.txt".format(code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all_extended.txt".format(code)) ## Select only some lines to speed up the execution (in a real analysis it is better not to do this) line_regions = line_regions[np.logical_or( line_regions['note'] == 'Ti 1', line_regions['note'] == 'Ti 2')] line_regions = ispec.adjust_linemasks(normalized_star_spectrum, line_regions, max_margin=0.5) # Read segments if we have them or... #segments = ispec.read_segment_regions(ispec_dir + "/input/regions/fe_lines_segments.txt") # ... or we can create the segments on the fly: segments = ispec.create_segments_around_lines(line_regions, margin=0.25) ### Add also regions from the wings of strong lines: ## H beta #hbeta_lines = ispec.read_line_regions(ispec_dir + "input/regions/wings_Hbeta.txt") #hbeta_segments = ispec.read_segment_regions(ispec_dir + "input/regions/wings_Hbeta_segments.txt") #line_regions = np.hstack((line_regions, hbeta_lines)) #segments = np.hstack((segments, hbeta_segments)) ## H alpha #halpha_lines = ispec.read_line_regions(ispec_dir + "input/regions/wings_Halpha.txt") #halpha_segments = ispec.read_segment_regions(ispec_dir + "input/regions/wings_Halpha_segments.txt") #line_regions = np.hstack((line_regions, halpha_lines)) #segments = np.hstack((segments, halpha_segments)) ## Magnesium triplet #mgtriplet_lines = ispec.read_line_regions(ispec_dir + "input/regions/wings_MgTriplet.txt") #mgtriplet_segments = ispec.read_segment_regions(ispec_dir + "input/regions/wings_MgTriplet_segments.txt") #line_regions = np.hstack((line_regions, mgtriplet_lines)) #segments = np.hstack((segments, mgtriplet_segments)) obs_spec, modeled_synth_spectrum, params, errors, abundances_found, loggf_found, status, stats_linemasks = \ ispec.model_spectrum(normalized_star_spectrum, star_continuum_model, \ modeled_layers_pack, atomic_linelist, isotopes, solar_abundances, free_abundances, linelist_free_loggf, initial_teff, \ initial_logg, initial_MH, initial_alpha, initial_vmic, initial_vmac, initial_vsini, \ initial_limb_darkening_coeff, initial_R, initial_vrad, free_params, segments=segments, \ linemasks=line_regions, \ enhance_abundances=True, \ use_errors = True, \ vmic_from_empirical_relation = False, \ vmac_from_empirical_relation = True, \ max_iterations=max_iterations, \ tmp_dir = None, \ code=code) expected_params = { 'teff': 5696.144535300913, 'logg': 4.35386512625295, 'MH': -0.117924251886487, 'alpha': 0.047169700754594805, 'vmic': 1.1383979614486783, 'vmac': 4.04, 'vsini': 2.0, 'limb_darkening_coeff': 0.6, 'R': 49936.32725781359 } for k, v in list(expected_params.items()): self.assertAlmostEqual(params[k], v) expected_errors = { 'teff': 66.38643184730074, 'logg': 0.10101410057739481, 'MH': 0.07728877921624414, 'alpha': 0.0, 'vmic': 0.10922339131594937, 'vmac': 0.0, 'vsini': 0.0, 'limb_darkening_coeff': 0.0, 'R': 3496.439438356713 } for k, v in list(expected_errors.items()): self.assertAlmostEqual(errors[k], v) self.assertEqual(len(stats_linemasks), 30)
def test_determine_loggf_line_by_line_using_synth_spectra(self): code = "spectrum" star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #--- Model spectra ---------------------------------------------------------- # Parameters initial_teff = 5771.0 initial_logg = 4.44 initial_MH = 0.00 initial_alpha = 0.00 initial_vmic = ispec.estimate_vmic(initial_teff, initial_logg, initial_MH) initial_vmac = ispec.estimate_vmac(initial_teff, initial_logg, initial_MH) initial_vsini = 1.60 # Sun initial_limb_darkening_coeff = 0.6 initial_R = to_resolution initial_vrad = 0 max_iterations = 6 # Selected model amtosphere, linelist and solar abundances #model = ispec_dir + "/input/atmospheres/MARCS/" model = ispec_dir + "/input/atmospheres/MARCS.GES/" #model = ispec_dir + "/input/atmospheres/MARCS.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Castelli/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kurucz/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kirby/" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.300_1100nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.1100_2400nm/atomic_lines.tsv" atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_hfs_iso.420_920nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_nohfs_noiso.420_920nm/atomic_lines.tsv" if "ATLAS" in model: solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.1998/stdatom.dat" else: # MARCS solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.2007/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2005/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2009/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Anders.1989/stdatom.dat" isotope_file = ispec_dir + "/input/isotopes/SPECTRUM.lst" # Load chemical information and linelist atomic_linelist = ispec.read_atomic_linelist( atomic_linelist_file, wave_base=np.min(star_spectrum['waveobs']), wave_top=np.max(star_spectrum['waveobs'])) atomic_linelist = atomic_linelist[ atomic_linelist['theoretical_depth'] >= 0.01] # Select lines that have some minimal contribution in the sun isotopes = ispec.read_isotope_data(isotope_file) # Load model atmospheres modeled_layers_pack = ispec.load_modeled_layers_pack(model) # Load SPECTRUM abundances solar_abundances = ispec.read_solar_abundances(solar_abundances_file) # Free parameters #free_params = ["teff", "logg", "MH", "vmic", "vmac", "vsini", "R", "vrad", "limb_darkening_coeff"] #free_params = ["vrad"] free_params = [] # Free individual element abundance (WARNING: it should be coherent with the selected line regions!) chemical_elements_file = ispec_dir + "/input/abundances/chemical_elements_symbols.dat" chemical_elements = ispec.read_chemical_elements( chemical_elements_file) # Line regions line_regions_with_atomic_data = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all_extended.txt" .format(code)) #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all_extended.txt".format(code)) # Select only the lines to get abundances from line_regions_with_atomic_data = line_regions_with_atomic_data[:5] line_regions_with_atomic_data = ispec.adjust_linemasks( normalized_star_spectrum, line_regions_with_atomic_data, max_margin=0.5) output_dirname = "example_loggf_line_by_line_%s" % (code, ) #ispec.mkdir_p(output_dirname) for i, line in enumerate(line_regions_with_atomic_data): # Directory and file names #element_name = "_".join(line['element'].split()) element_name = "_".join(line['note'].split()) common_filename = "example_" + code + "_individual_" + element_name + "_%.4f" % line[ 'wave_peak'] # Free individual element abundance (WARNING: it should be coherent with the selected line regions!) free_abundances = None # Line by line individual_line_regions = line_regions_with_atomic_data[ i:i + 1] # Keep recarray structure linelist_free_loggf = line_regions_with_atomic_data[ i:i + 1] # Keep recarray structure # Filter the line that we want to determine the loggf from the global atomic linelist lfilter = atomic_linelist['element'] == linelist_free_loggf[ 'element'][0] for key in [ 'wave_nm', 'lower_state_eV', 'loggf', 'stark', 'rad', 'waals' ]: lfilter = np.logical_and( lfilter, np.abs(atomic_linelist[key] - linelist_free_loggf[key][0]) < 1e-9) # Segment segments = ispec.create_segments_around_lines( individual_line_regions, margin=0.25) wfilter = ispec.create_wavelength_filter( normalized_star_spectrum, regions=segments) # Only use the segment obs_spec, modeled_synth_spectrum, params, errors, abundances_found, loggf_found, status, stats_linemasks = \ ispec.model_spectrum(normalized_star_spectrum[wfilter], star_continuum_model, \ modeled_layers_pack, atomic_linelist[~lfilter], isotopes, solar_abundances, free_abundances, linelist_free_loggf, initial_teff, \ initial_logg, initial_MH, initial_alpha, initial_vmic, initial_vmac, initial_vsini, \ initial_limb_darkening_coeff, initial_R, initial_vrad, free_params, segments=segments, \ linemasks=individual_line_regions, \ enhance_abundances=True, \ use_errors = True, \ vmic_from_empirical_relation = False, \ vmac_from_empirical_relation = False, \ max_iterations=max_iterations, \ tmp_dir = None, \ code=code) self.assertAlmostEqual(loggf_found['loggf'][0], -1.0743873027191777) self.assertAlmostEqual(loggf_found['eloggf'][0], 0.11414696354921147) self.assertEqual(len(loggf_found['loggf']), 1) self.assertEqual(individual_line_regions['lower_state_eV'][0], loggf_found['linelist']['lower_state_eV'][0]) break
def test_determine_abundances_using_synth_spectra(self): code = "spectrum" star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #--- Model spectra ---------------------------------------------------------- # Parameters initial_teff = 5771.0 initial_logg = 4.44 initial_MH = 0.00 initial_alpha = 0.00 initial_vmic = ispec.estimate_vmic(initial_teff, initial_logg, initial_MH) initial_vmac = ispec.estimate_vmac(initial_teff, initial_logg, initial_MH) initial_vsini = 1.60 # Sun initial_limb_darkening_coeff = 0.6 initial_R = to_resolution initial_vrad = 0 max_iterations = 6 # Selected model amtosphere, linelist and solar abundances #model = ispec_dir + "/input/atmospheres/MARCS/" model = ispec_dir + "/input/atmospheres/MARCS.GES/" #model = ispec_dir + "/input/atmospheres/MARCS.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Castelli/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kurucz/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kirby/" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.300_1100nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.1100_2400nm/atomic_lines.tsv" atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_hfs_iso.420_920nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_nohfs_noiso.420_920nm/atomic_lines.tsv" if "ATLAS" in model: solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.1998/stdatom.dat" else: # MARCS solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.2007/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2005/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2009/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Anders.1989/stdatom.dat" isotope_file = ispec_dir + "/input/isotopes/SPECTRUM.lst" # Load chemical information and linelist atomic_linelist = ispec.read_atomic_linelist( atomic_linelist_file, wave_base=np.min(star_spectrum['waveobs']), wave_top=np.max(star_spectrum['waveobs'])) atomic_linelist = atomic_linelist[ atomic_linelist['theoretical_depth'] >= 0.01] # Select lines that have some minimal contribution in the sun isotopes = ispec.read_isotope_data(isotope_file) # Load model atmospheres modeled_layers_pack = ispec.load_modeled_layers_pack(model) # Load SPECTRUM abundances solar_abundances = ispec.read_solar_abundances(solar_abundances_file) # Free parameters #free_params = ["teff", "logg", "MH", "vmic", "vmac", "vsini", "R", "vrad", "limb_darkening_coeff"] free_params = ["vrad"] #free_params = [] # Free individual element abundance (WARNING: it should be coherent with the selected line regions!) chemical_elements_file = ispec_dir + "/input/abundances/chemical_elements_symbols.dat" chemical_elements = ispec.read_chemical_elements( chemical_elements_file) element_name = "Ca" free_abundances = ispec.create_free_abundances_structure( [element_name], chemical_elements, solar_abundances) free_abundances['Abund'] += initial_MH # Scale to metallicity linelist_free_loggf = None # Line regions line_regions = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all.txt".format( code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all_extended.txt".format(code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all.txt".format(code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all_extended.txt".format(code)) # Select only the lines to get abundances from line_regions = line_regions[np.logical_or( line_regions['note'] == element_name + ' 1', line_regions['note'] == element_name + ' 2')] line_regions = ispec.adjust_linemasks(normalized_star_spectrum, line_regions, max_margin=0.5) # Read segments if we have them or... #segments = ispec.read_segment_regions(ispec_dir + "/input/regions/fe_lines_segments.txt") # ... or we can create the segments on the fly: segments = ispec.create_segments_around_lines(line_regions, margin=0.25) obs_spec, modeled_synth_spectrum, params, errors, abundances_found, loggf_found, status, stats_linemasks = \ ispec.model_spectrum(normalized_star_spectrum, star_continuum_model, \ modeled_layers_pack, atomic_linelist, isotopes, solar_abundances, free_abundances, linelist_free_loggf, initial_teff, \ initial_logg, initial_MH, initial_alpha, initial_vmic, initial_vmac, initial_vsini, \ initial_limb_darkening_coeff, initial_R, initial_vrad, free_params, segments=segments, \ linemasks=line_regions, \ enhance_abundances=True, \ use_errors = True, \ vmic_from_empirical_relation = False, \ vmac_from_empirical_relation = False, \ max_iterations=max_iterations, \ tmp_dir = None, \ code=code) expected_params = { 'teff': 5771.0, 'logg': 4.44, 'MH': 0.0, 'alpha': 0.0, 'vmic': 1.07, 'vmac': 4.19, 'vsini': 1.6, 'limb_darkening_coeff': 0.6, 'R': 47000.0, 'vrad0000': -0.009293697395991595, 'vrad0001': -0.06018526081728252, 'vrad0002': -0.015666491320596353, 'vrad0003': -0.055193632795656256, 'vrad0004': -0.1567689404172516, 'vrad0005': -0.22508061064189286, 'vrad0006': -0.20359311863771612, 'vrad0007': -0.16078450322612126 } for k, v in list(expected_params.items()): self.assertAlmostEqual(params[k], v) expected_errors = { 'teff': 0.0, 'logg': 0.0, 'MH': 0.0, 'alpha': 0.0, 'vmic': 0.0, 'vmac': 0.0, 'vsini': 0.0, 'limb_darkening_coeff': 0.0, 'R': 0.0, 'vrad0000': 2.2914331925224816, 'vrad0001': 0.6770488621090028, 'vrad0002': 0.2767472596825708, 'vrad0003': 1.0820599330375968, 'vrad0004': 0.47734411482243877, 'vrad0005': 0.2585031799872256, 'vrad0006': 0.46187116575854853, 'vrad0007': 0.23921192411257394 } for k, v in list(expected_errors.items()): self.assertAlmostEqual(errors[k], v) self.assertEqual(len(stats_linemasks), 8) self.assertEqual(abundances_found['element'][0], 'Ca') self.assertAlmostEqual(abundances_found['[X/H]'][0], -0.0020078068382556324) self.assertAlmostEqual(abundances_found['[X/Fe]'][0], -0.0020078068382556324) self.assertAlmostEqual(abundances_found['e[X/H]'][0], 0.027149612080779945) self.assertAlmostEqual(abundances_found['e[X/Fe]'][0], 0.027149612080779945)
def test_determine_astrophysical_parameters_using_grid(self): star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #star_spectrum = ispec.read_spectrum(ispec_dir + "/input/spectra/examples/NARVAL_Arcturus.txt.gz") #star_spectrum = ispec.read_spectrum(ispec_dir + "/input/spectra/examples/NARVAL_muCas.txt.gz") #star_spectrum = ispec.read_spectrum(ispec_dir + "/input/spectra/examples/NARVAL_muLeo.txt.gz") #star_spectrum = ispec.read_spectrum(ispec_dir + "/input/spectra/examples/HARPS.GBOG_Procyon.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #--- Model spectra ---------------------------------------------------------- # Parameters initial_teff = 5750.0 initial_logg = 4.5 initial_MH = 0.00 initial_alpha = 0.00 initial_vmic = ispec.estimate_vmic(initial_teff, initial_logg, initial_MH) initial_vmac = ispec.estimate_vmac(initial_teff, initial_logg, initial_MH) initial_vsini = 2.0 initial_limb_darkening_coeff = 0.6 initial_R = to_resolution initial_vrad = 0 max_iterations = 20 code = "grid" precomputed_grid_dir = ispec_dir + "/input/grid/SPECTRUM_MARCS.GES_GESv6_atom_hfs_iso.480_680nm_light/" atomic_linelist = None isotopes = None modeled_layers_pack = None solar_abundances = None free_abundances = None linelist_free_loggf = None # Free parameters (vmic cannot be used as a free parameter when using a spectral grid) #free_params = ["teff", "logg", "MH", "alpha", "vmic", "vmac", "vsini", "R", "vrad", "limb_darkening_coeff"] free_params = ["teff", "logg", "MH", "alpha", "vmic", "R"] # Line regions line_regions = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all.txt".format( code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all_extended.txt".format(code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all.txt".format(code)) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all_extended.txt".format(code)) ## Select only some lines to speed up the execution (in a real analysis it is better not to do this) #line_regions = line_regions[np.logical_or(line_regions['note'] == 'Ti 1', line_regions['note'] == 'Ti 2')] #line_regions = ispec.adjust_linemasks(normalized_star_spectrum, line_regions, max_margin=0.5) # Read segments if we have them or... #segments = ispec.read_segment_regions(ispec_dir + "/input/regions/fe_lines_segments.txt") # ... or we can create the segments on the fly: segments = ispec.create_segments_around_lines(line_regions, margin=0.25) ## Add also regions from the wings of strong lines: # H beta hbeta_lines = ispec.read_line_regions(ispec_dir + "input/regions/wings_Hbeta.txt") hbeta_segments = ispec.read_segment_regions( ispec_dir + "input/regions/wings_Hbeta_segments.txt") line_regions = np.hstack((line_regions, hbeta_lines)) segments = np.hstack((segments, hbeta_segments)) # H alpha halpha_lines = ispec.read_line_regions( ispec_dir + "input/regions/wings_Halpha.txt") halpha_segments = ispec.read_segment_regions( ispec_dir + "input/regions/wings_Halpha_segments.txt") line_regions = np.hstack((line_regions, halpha_lines)) segments = np.hstack((segments, halpha_segments)) # Magnesium triplet mgtriplet_lines = ispec.read_line_regions( ispec_dir + "input/regions/wings_MgTriplet.txt") mgtriplet_segments = ispec.read_segment_regions( ispec_dir + "input/regions/wings_MgTriplet_segments.txt") line_regions = np.hstack((line_regions, mgtriplet_lines)) segments = np.hstack((segments, mgtriplet_segments)) obs_spec, modeled_synth_spectrum, params, errors, abundances_found, loggf_found, status, stats_linemasks = \ ispec.model_spectrum(normalized_star_spectrum, star_continuum_model, \ modeled_layers_pack, atomic_linelist, isotopes, solar_abundances, free_abundances, linelist_free_loggf, initial_teff, \ initial_logg, initial_MH, initial_alpha, initial_vmic, initial_vmac, initial_vsini, \ initial_limb_darkening_coeff, initial_R, initial_vrad, free_params, segments=segments, \ linemasks=line_regions, \ enhance_abundances=False, \ use_errors = True, \ vmic_from_empirical_relation = False, \ vmac_from_empirical_relation = True, \ max_iterations=max_iterations, \ tmp_dir = None, \ code=code, precomputed_grid_dir=precomputed_grid_dir) expected_params = { 'teff': 5848.516352941799, 'logg': 4.47140586507073, 'MH': 0.021745200217247945, 'alpha': 0.0, 'vmic': 0.5617098008018283, 'vmac': 4.5, 'vsini': 2.0, 'limb_darkening_coeff': 0.6, 'R': 78395.52968455742 } for k, v in list(expected_params.items()): self.assertAlmostEqual(params[k], v) expected_errors = { 'teff': 16.061649602869444, 'logg': 0.028408456932473077, 'MH': 0.007324730574204324, 'alpha': 0.007733907152934892, 'vmic': 0.043996803165640905, 'vmac': 0.0, 'vsini': 0.0, 'limb_darkening_coeff': 0.0, 'R': 3898.724894322937 } for k, v in list(expected_errors.items()): self.assertAlmostEqual(errors[k], v) self.assertEqual(len(stats_linemasks), 337)
def _determine_abundances_from_ew(self, code): use_ares = False star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Telluric velocity shift determination from spectrum -------------------------- # - Telluric telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" telluric_linelist = ispec.read_telluric_linelist( telluric_linelist_file, minimum_depth=0.0) models, ccf = ispec.cross_correlate_with_mask(star_spectrum, telluric_linelist, \ lower_velocity_limit=-100, upper_velocity_limit=100, \ velocity_step=0.5, mask_depth=0.01, \ fourier = False, only_one_peak = True) vel_telluric = np.round(models[0].mu(), 2) # km/s vel_telluric_err = np.round(models[0].emu(), 2) # km/s #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm #from_resolution = 80000 from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" #telluric_linelist = ispec.read_telluric_linelist(telluric_linelist_file, minimum_depth=0.01) #vel_telluric = 17.79 # km/s #telluric_linelist = None #vel_telluric = None #--- Read lines and adjust them ------------------------------------------------ if code in ['width', 'moog']: line_regions_with_atomic_data = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_ew_ispec_good_for_params_all_extended.txt" .format(code)) #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_ew_ispec_good_for_params_all_extended.txt".format(code)) else: line_regions_with_atomic_data = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all_extended.txt" .format(code)) #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all_extended.txt".format(code)) # Select only iron lines line_regions_with_atomic_data = line_regions_with_atomic_data[ np.logical_or(line_regions_with_atomic_data['note'] == "Fe 1", line_regions_with_atomic_data['note'] == "Fe 2")] smoothed_star_spectrum = ispec.convolve_spectrum( star_spectrum, 2 * to_resolution) line_regions_with_atomic_data = ispec.adjust_linemasks( smoothed_star_spectrum, line_regions_with_atomic_data, max_margin=0.5) #--- Fit the lines but do NOT cross-match with any atomic linelist since they already have that information linemasks = ispec.fit_lines(line_regions_with_atomic_data, normalized_star_spectrum, star_continuum_model, \ atomic_linelist = None, \ max_atomic_wave_diff = 0.005, \ telluric_linelist = telluric_linelist, \ check_derivatives = False, \ vel_telluric = vel_telluric, discard_gaussian=False, \ smoothed_spectrum=None, \ discard_voigt=True, \ free_mu=True, crossmatch_with_mu=False, closest_match=False) # Discard bad masks flux_peak = normalized_star_spectrum['flux'][linemasks['peak']] flux_base = normalized_star_spectrum['flux'][linemasks['base']] flux_top = normalized_star_spectrum['flux'][linemasks['top']] bad_mask = np.logical_or( linemasks['wave_peak'] <= linemasks['wave_base'], linemasks['wave_peak'] >= linemasks['wave_top']) bad_mask = np.logical_or(bad_mask, flux_peak >= flux_base) bad_mask = np.logical_or(bad_mask, flux_peak >= flux_top) linemasks = linemasks[~bad_mask] # Exclude lines with EW equal to zero rejected_by_zero_ew = (linemasks['ew'] == 0) linemasks = linemasks[~rejected_by_zero_ew] # Exclude lines that may be affected by tellurics rejected_by_telluric_line = (linemasks['telluric_wave_peak'] != 0) linemasks = linemasks[~rejected_by_telluric_line] linemasks = linemasks[:20] if use_ares: # Replace the measured equivalent widths by the ones computed by ARES old_linemasks = linemasks.copy() ### Different rejection parameters (check ARES papers): ## - http://adsabs.harvard.edu/abs/2007A%26A...469..783S ## - http://adsabs.harvard.edu/abs/2015A%26A...577A..67S #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="0.995", tmp_dir=None, verbose=0) #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="3;5764,5766,6047,6052,6068,6076", tmp_dir=None, verbose=0) snr = 50 linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="%s" % (snr), tmp_dir=None, verbose=0) #--- Determining abundances by EW of the previously fitted lines --------------- # Parameters teff = 5777.0 logg = 4.44 MH = 0.00 alpha = 0.00 microturbulence_vel = 1.0 # Selected model amtosphere and solar abundances #model = ispec_dir + "/input/atmospheres/MARCS/" model = ispec_dir + "/input/atmospheres/MARCS.GES/" #model = ispec_dir + "/input/atmospheres/MARCS.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Castelli/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kurucz/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kirby/" if "ATLAS" in model: solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.1998/stdatom.dat" else: # MARCS solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.2007/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2005/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2009/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Anders.1989/stdatom.dat" # Load model atmospheres modeled_layers_pack = ispec.load_modeled_layers_pack(model) # Load SPECTRUM abundances solar_abundances = ispec.read_solar_abundances(solar_abundances_file) # Validate parameters if not ispec.valid_atmosphere_target(modeled_layers_pack, { 'teff': teff, 'logg': logg, 'MH': MH, 'alpha': alpha }): msg = "The specified effective temperature, gravity (log g) and metallicity [M/H] \ fall out of theatmospheric models." print(msg) # Prepare atmosphere model atmosphere_layers = ispec.interpolate_atmosphere_layers( modeled_layers_pack, { 'teff': teff, 'logg': logg, 'MH': MH, 'alpha': alpha }, code=code) spec_abund, normal_abund, x_over_h, x_over_fe = ispec.determine_abundances(atmosphere_layers, \ teff, logg, MH, alpha, linemasks, solar_abundances, microturbulence_vel = microturbulence_vel, \ verbose=1, code=code) return linemasks, x_over_h
def determine_parameters(spec_id, lines_id): #code = "synthe" code = "spectrum" star_spectrum = ispec.read_spectrum(spec_id) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") normalized_star_spectrum = ispec.normalize_spectrum(star_spectrum, star_continuum_model, consider_continuum_errors=False) #--- Model spectra ---------------------------------------------------------- params = [] with open('config.txt', 'r') as cfile: for line in cfile: params.append(float(str(line)[:-1])) # Parameters initial_teff = params[0] initial_logg = params[1] initial_MH = params[2] initial_vmic = params[3] initial_vmac = params[4] initial_vsini = params[5] initial_limb_darkening_coeff = params[6] initial_R = params[7] initial_vrad = params[8] max_iterations = params[9] # Selected model amtosphere, linelist and solar abundances #model = ispec_dir + "/input/atmospheres/MARCS/modeled_layers_pack.dump" model = ispec_dir + "/input/atmospheres/MARCS.GES/modeled_layers_pack.dump" #model = ispec_dir + "/input/atmospheres/MARCS.APOGEE/modeled_layers_pack.dump" #model = ispec_dir + "/input/atmospheres/ATLAS9.APOGEE/modeled_layers_pack.dump" #model = ispec_dir + "/input/atmospheres/ATLAS9.Castelli/modeled_layers_pack.dump" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kurucz/modeled_layers_pack.dump" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kirby/modeled_layers_pack.dump" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.300_1100nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.1100_2400nm/atomic_lines.tsv" atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv5_atom_hfs_iso.420_920nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv5_atom_nohfs_noiso.420_920nm/atomic_lines.tsv" solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.2007/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2005/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2009/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.1998/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Anders.1989/stdatom.dat" isotope_file = ispec_dir + "/input/isotopes/SPECTRUM.lst" # Load chemical information and linelist atomic_linelist = ispec.read_atomic_linelist(atomic_linelist_file, wave_base=np.min(star_spectrum['waveobs']), wave_top=np.max(star_spectrum['waveobs'])) atomic_linelist = atomic_linelist[atomic_linelist['theoretical_depth'] >= 0.01] # Select lines that have some minimal contribution in the sun isotopes = ispec.read_isotope_data(isotope_file) # Load model atmospheres modeled_layers_pack = ispec.load_modeled_layers_pack(model) # Load SPECTRUM abundances solar_abundances = ispec.read_solar_abundances(solar_abundances_file) # Free parameters #free_params = ["teff", "logg", "MH", "vmic", "vmac", "vsini", "R", "vrad", "limb_darkening_coeff"] free_params = ["teff", "logg", "MH", "vmic", "vmac", "vsini"] # Free individual element abundance free_abundances = None linelist_free_loggf = None # Line regions line_regions = ispec.read_line_regions(lines_id) #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/spectrum_synth_turbospectrum_synth_sme_synth_moog_synth_synthe_synth_good_for_params_all_extended.txt") # Select only some lines to speed up the execution (in a real analysis it is better not to do this) #line_regions = line_regions[np.logical_or(line_regions['note'] == 'Ti 1', line_regions['note'] == 'Ti 2')] #line_regions = ispec.adjust_linemasks(normalized_star_spectrum, line_regions, max_margin=0.5) # Read segments if we have them or... #segments = ispec.read_segment_regions(ispec_dir + "/input/regions/fe_lines_segments.txt") # ... or we can create the segments on the fly: segments = ispec.create_segments_around_lines(line_regions, margin=0.25) obs_spec, modeled_synth_spectrum, params, errors, abundances_found, loggf_found, status, stats_linemasks = \ ispec.model_spectrum(normalized_star_spectrum, star_continuum_model, \ modeled_layers_pack, atomic_linelist, isotopes, solar_abundances, free_abundances, linelist_free_loggf, initial_teff, \ initial_logg, initial_MH, initial_vmic, initial_vmac, initial_vsini, \ initial_limb_darkening_coeff, initial_R, initial_vrad, free_params, segments=segments, \ linemasks=line_regions, \ enhance_abundances=True, \ use_errors = True, \ vmic_from_empirical_relation = False, \ vmac_from_empirical_relation = False, \ max_iterations=max_iterations, \ tmp_dir = None, \ code=code) ##--- Save results ------------------------------------------------------------- logging.info("Saving results...") #dump_file = "example_results_synth_%s.dump" % (code) #ispec.save_results(dump_file, (params, errors, abundances_found, loggf_found, status, stats_linemasks)) # If we need to restore the results from another script: #params, errors, abundances_found, loggf_found, status, stats_linemasks = ispec.restore_results(dump_file) #logging.info("Saving synthetic spectrum...") #synth_filename = "example_modeled_synth_%s.fits" % (code) #ispec.write_spectrum(modeled_synth_spectrum, synth_filename) parameters = "\n" + str(params) parameter_errors = "\n" + str(errors) file_id = spec_id + "_info.txt" with open(file_id, "w") as savefile: savefile.write(parameters) savefile.write(parameter_errors)
def test_fit_lines_determine_ew_and_crossmatch_with_atomic_data(self): use_ares = False star_spectrum = ispec.read_spectrum(ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Telluric velocity shift determination from spectrum -------------------------- # - Telluric telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" telluric_linelist = ispec.read_telluric_linelist(telluric_linelist_file, minimum_depth=0.0) models, ccf = ispec.cross_correlate_with_mask(star_spectrum, telluric_linelist, \ lower_velocity_limit=-100, upper_velocity_limit=100, \ velocity_step=0.5, mask_depth=0.01, \ fourier = False, only_one_peak = True) vel_telluric = np.round(models[0].mu(), 2) # km/s vel_telluric_err = np.round(models[0].emu(), 2) # km/s #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = 80000 # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order='median+max' median_wave_range=0.05 max_wave_range=1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum(star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #--- Fit lines ----------------------------------------------------------------- #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.300_1100nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.1100_2400nm/atomic_lines.tsv" atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_hfs_iso.420_920nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_nohfs_noiso.420_920nm/atomic_lines.tsv" # Read atomic_linelist = ispec.read_atomic_linelist(atomic_linelist_file, wave_base=np.min(star_spectrum['waveobs']), wave_top=np.max(star_spectrum['waveobs'])) atomic_linelist = atomic_linelist[atomic_linelist['theoretical_depth'] >= 0.01] # Select lines that have some minimal contribution in the sun #telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" #telluric_linelist = ispec.read_telluric_linelist(telluric_linelist_file, minimum_depth=0.01) #vel_telluric = 17.79 # km/s #telluric_linelist = None #vel_telluric = None line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/moog_synth_good_for_params_all.txt") #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/width_synth_good_for_params_all.txt") #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/moog_synth_good_for_params_all.txt") #line_regions = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/width_synth_good_for_params_all.txt") line_regions = ispec.adjust_linemasks(normalized_star_spectrum, line_regions, max_margin=0.5) linemasks = ispec.fit_lines(line_regions, normalized_star_spectrum, star_continuum_model, \ atomic_linelist = atomic_linelist, \ #max_atomic_wave_diff = 0.005, \ max_atomic_wave_diff = 0.00, \ telluric_linelist = telluric_linelist, \ smoothed_spectrum = None, \ check_derivatives = False, \ vel_telluric = vel_telluric, discard_gaussian=False, \ discard_voigt=True, \ free_mu=True, crossmatch_with_mu=False, closest_match=False) # Discard lines that are not cross matched with the same original element stored in the note linemasks = linemasks[linemasks['element'] == line_regions['note']] # Exclude lines that have not been successfully cross matched with the atomic data # because we cannot calculate the chemical abundance (it will crash the corresponding routines) rejected_by_atomic_line_not_found = (linemasks['wave_nm'] == 0) linemasks = linemasks[~rejected_by_atomic_line_not_found] # Exclude lines with EW equal to zero rejected_by_zero_ew = (linemasks['ew'] == 0) linemasks = linemasks[~rejected_by_zero_ew] # Exclude lines that may be affected by tellurics rejected_by_telluric_line = (linemasks['telluric_wave_peak'] != 0) linemasks = linemasks[~rejected_by_telluric_line] if use_ares: # Replace the measured equivalent widths by the ones computed by ARES old_linemasks = linemasks.copy() ### Different rejection parameters (check ARES papers): ## - http://adsabs.harvard.edu/abs/2007A%26A...469..783S ## - http://adsabs.harvard.edu/abs/2015A%26A...577A..67S #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="0.995", tmp_dir=None, verbose=0) #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="3;5764,5766,6047,6052,6068,6076", tmp_dir=None, verbose=0) snr = 50 linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="%s" % (snr), tmp_dir=None, verbose=0) self.assertEqual(len(linemasks), 281) self.assertAlmostEqual(linemasks['ew'][0], 68.48284589709996) self.assertAlmostEqual(linemasks['ew'][-3], 46.17583047097995) self.assertEqual(linemasks['element'][0], 'Fe 1') self.assertEqual(linemasks['element'][-3], 'Si 1') self.assertAlmostEqual(linemasks['loggf'][0], -1.028) self.assertAlmostEqual(linemasks['loggf'][-3], -1.062)
def test_determine_astrophysical_parameters_from_ew(self): code = "moog" use_ares = False star_spectrum = ispec.read_spectrum( ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum( ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Telluric velocity shift determination from spectrum -------------------------- # - Telluric telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" telluric_linelist = ispec.read_telluric_linelist( telluric_linelist_file, minimum_depth=0.0) models, ccf = ispec.cross_correlate_with_mask(star_spectrum, telluric_linelist, \ lower_velocity_limit=-100, upper_velocity_limit=100, \ velocity_step=0.5, mask_depth=0.01, \ fourier = False, only_one_peak = True) vel_telluric = np.round(models[0].mu(), 2) # km/s vel_telluric_err = np.round(models[0].emu(), 2) # km/s #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm #from_resolution = 80000 from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order = 'median+max' median_wave_range = 0.05 max_wave_range = 1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum( star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" #telluric_linelist = ispec.read_telluric_linelist(telluric_linelist_file, minimum_depth=0.01) #vel_telluric = 17.79 # km/s #telluric_linelist = None #vel_telluric = None #--- Read lines and adjust them ------------------------------------------------ if code in ['width', 'moog']: line_regions_with_atomic_data = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_ew_ispec_good_for_params_all_extended.txt" .format(code)) #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_ew_ispec_good_for_params_all_extended.txt".format(code)) else: line_regions_with_atomic_data = ispec.read_line_regions( ispec_dir + "/input/regions/47000_GES/{}_synth_good_for_params_all_extended.txt" .format(code)) #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/{}_synth_good_for_params_all_extended.txt".format(code)) # Select only iron lines line_regions_with_atomic_data = line_regions_with_atomic_data[ np.logical_or(line_regions_with_atomic_data['note'] == "Fe 1", line_regions_with_atomic_data['note'] == "Fe 2")] smoothed_star_spectrum = ispec.convolve_spectrum( star_spectrum, 2 * to_resolution) line_regions_with_atomic_data = ispec.adjust_linemasks( smoothed_star_spectrum, line_regions_with_atomic_data, max_margin=0.5) #--- Fit the lines but do NOT cross-match with any atomic linelist since they already have that information linemasks = ispec.fit_lines(line_regions_with_atomic_data, normalized_star_spectrum, star_continuum_model, \ atomic_linelist = None, \ max_atomic_wave_diff = 0.005, \ telluric_linelist = telluric_linelist, \ check_derivatives = False, \ vel_telluric = vel_telluric, discard_gaussian=False, \ smoothed_spectrum=None, \ discard_voigt=True, \ free_mu=True, crossmatch_with_mu=False, closest_match=False) # Discard bad masks flux_peak = normalized_star_spectrum['flux'][linemasks['peak']] flux_base = normalized_star_spectrum['flux'][linemasks['base']] flux_top = normalized_star_spectrum['flux'][linemasks['top']] bad_mask = np.logical_or( linemasks['wave_peak'] <= linemasks['wave_base'], linemasks['wave_peak'] >= linemasks['wave_top']) bad_mask = np.logical_or(bad_mask, flux_peak >= flux_base) bad_mask = np.logical_or(bad_mask, flux_peak >= flux_top) linemasks = linemasks[~bad_mask] # Exclude lines with EW equal to zero rejected_by_zero_ew = (linemasks['ew'] == 0) linemasks = linemasks[~rejected_by_zero_ew] # Exclude lines that may be affected by tellurics rejected_by_telluric_line = (linemasks['telluric_wave_peak'] != 0) linemasks = linemasks[~rejected_by_telluric_line] if use_ares: # Replace the measured equivalent widths by the ones computed by ARES old_linemasks = linemasks.copy() ### Different rejection parameters (check ARES papers): ## - http://adsabs.harvard.edu/abs/2007A%26A...469..783S ## - http://adsabs.harvard.edu/abs/2015A%26A...577A..67S #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="0.995", tmp_dir=None, verbose=0) #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="3;5764,5766,6047,6052,6068,6076", tmp_dir=None, verbose=0) snr = 50 linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="%s" % (snr), tmp_dir=None, verbose=0) #--- Model spectra from EW -------------------------------------------------- # Parameters initial_teff = 5777.0 initial_logg = 4.44 initial_MH = 0.00 initial_alpha = 0.00 initial_vmic = ispec.estimate_vmic(initial_teff, initial_logg, initial_MH) max_iterations = 10 # Selected model amtosphere, linelist and solar abundances #model = ispec_dir + "/input/atmospheres/MARCS/" model = ispec_dir + "/input/atmospheres/MARCS.GES/" #model = ispec_dir + "/input/atmospheres/MARCS.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.APOGEE/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Castelli/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kurucz/" #model = ispec_dir + "/input/atmospheres/ATLAS9.Kirby/" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.300_1100nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/VALD.1100_2400nm/atomic_lines.tsv" atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_hfs_iso.420_920nm/atomic_lines.tsv" #atomic_linelist_file = ispec_dir + "/input/linelists/transitions/GESv6_atom_nohfs_noiso.420_920nm/atomic_lines.tsv" if "ATLAS" in model: solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.1998/stdatom.dat" else: # MARCS solar_abundances_file = ispec_dir + "/input/abundances/Grevesse.2007/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2005/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Asplund.2009/stdatom.dat" #solar_abundances_file = ispec_dir + "/input/abundances/Anders.1989/stdatom.dat" # Load model atmospheres modeled_layers_pack = ispec.load_modeled_layers_pack(model) # Load SPECTRUM abundances solar_abundances = ispec.read_solar_abundances(solar_abundances_file) # Validate parameters if not ispec.valid_atmosphere_target( modeled_layers_pack, { 'teff': initial_teff, 'logg': initial_logg, 'MH': initial_MH, 'alpha': initial_alpha }): msg = "The specified effective temperature, gravity (log g) and metallicity [M/H] \ fall out of theatmospheric models." print(msg) # Reduced equivalent width # Filter too weak/strong lines # * Criteria presented in paper of GALA #efilter = np.logical_and(linemasks['ewr'] >= -5.8, linemasks['ewr'] <= -4.65) efilter = np.logical_and(linemasks['ewr'] >= -6.0, linemasks['ewr'] <= -4.3) # Filter high excitation potential lines # * Criteria from Eric J. Bubar "Equivalent Width Abundance Analysis In Moog" efilter = np.logical_and(efilter, linemasks['lower_state_eV'] <= 5.0) efilter = np.logical_and(efilter, linemasks['lower_state_eV'] >= 0.5) ## Filter also bad fits efilter = np.logical_and(efilter, linemasks['rms'] < 1.00) # no flux noflux = normalized_star_spectrum['flux'][linemasks['peak']] < 1.0e-10 efilter = np.logical_and(efilter, np.logical_not(noflux)) unfitted = linemasks['fwhm'] == 0 efilter = np.logical_and(efilter, np.logical_not(unfitted)) results = ispec.model_spectrum_from_ew(linemasks[efilter], modeled_layers_pack, \ solar_abundances, initial_teff, initial_logg, initial_MH, initial_alpha, initial_vmic, \ free_params=["teff", "logg", "vmic"], \ adjust_model_metalicity=True, \ max_iterations=max_iterations, \ enhance_abundances=True, \ #outliers_detection = "robust", \ #outliers_weight_limit = 0.90, \ outliers_detection = "sigma_clipping", \ #sigma_level = 3, \ tmp_dir = None, \ code=code) params, errors, status, x_over_h, selected_x_over_h, fitted_lines_params, used_linemasks = results expected_params = { 'teff': 5825.366401775263, 'logg': 4.3929210834771535, 'MH': 0.03500000000000014, 'alpha': 0.0, 'vmic': 1.1670939448402673 } for k, v in list(expected_params.items()): self.assertAlmostEqual(params[k], v) expected_errors = { 'teff': 59.030776466850426, 'logg': 0.08775700534919817, 'MH': 0.0606561589029185, 'alpha': 0.0, 'vmic': 0.03900548810240552 } for k, v in list(expected_errors.items()): self.assertAlmostEqual(errors[k], v)
def test_fit_lines_already_crossmatched_with_atomic_data_and_determine_ew(self): use_ares = False star_spectrum = ispec.read_spectrum(ispec_dir + "/input/spectra/examples/NARVAL_Sun_Vesta-1.txt.gz") #--- Radial Velocity determination with template ------------------------------- # - Read synthetic template #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Arcturus.372_926nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Atlas.Sun.372_926nm/template.txt.gz") template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/NARVAL.Sun.370_1048nm/template.txt.gz") #template = ispec.read_spectrum(ispec_dir + "/input/spectra/templates/Synth.Sun.300_1100nm/template.txt.gz") models, ccf = ispec.cross_correlate_with_template(star_spectrum, template, \ lower_velocity_limit=-200, upper_velocity_limit=200, \ velocity_step=1.0, fourier=False) # Number of models represent the number of components components = len(models) # First component: rv = np.round(models[0].mu(), 2) # km/s rv_err = np.round(models[0].emu(), 2) # km/s #--- Radial Velocity correction ------------------------------------------------ star_spectrum = ispec.correct_velocity(star_spectrum, rv) #--- Telluric velocity shift determination from spectrum -------------------------- # - Telluric telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" telluric_linelist = ispec.read_telluric_linelist(telluric_linelist_file, minimum_depth=0.0) models, ccf = ispec.cross_correlate_with_mask(star_spectrum, telluric_linelist, \ lower_velocity_limit=-100, upper_velocity_limit=100, \ velocity_step=0.5, mask_depth=0.01, \ fourier = False, only_one_peak = True) vel_telluric = np.round(models[0].mu(), 2) # km/s vel_telluric_err = np.round(models[0].emu(), 2) # km/s #--- Resolution degradation ---------------------------------------------------- # NOTE: The line selection was built based on a solar spectrum with R ~ 47,000 and GES/VALD atomic linelist. from_resolution = 80000 to_resolution = 47000 star_spectrum = ispec.convolve_spectrum(star_spectrum, to_resolution, from_resolution) #--- Continuum fit ------------------------------------------------------------- model = "Splines" # "Polynomy" degree = 2 nknots = None # Automatic: 1 spline every 5 nm from_resolution = to_resolution # Strategy: Filter first median values and secondly MAXIMUMs in order to find the continuum order='median+max' median_wave_range=0.05 max_wave_range=1.0 star_continuum_model = ispec.fit_continuum(star_spectrum, from_resolution=from_resolution, \ nknots=nknots, degree=degree, \ median_wave_range=median_wave_range, \ max_wave_range=max_wave_range, \ model=model, order=order, \ automatic_strong_line_detection=True, \ strong_line_probability=0.5, \ use_errors_for_fitting=True) #--- Normalize ------------------------------------------------------------- normalized_star_spectrum = ispec.normalize_spectrum(star_spectrum, star_continuum_model, consider_continuum_errors=False) # Use a fixed value because the spectrum is already normalized star_continuum_model = ispec.fit_continuum(star_spectrum, fixed_value=1.0, model="Fixed value") #--- Read lines with atomic data ------------------------------------------------ line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/moog_synth_good_for_params_all_extended.txt") #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_GES/width_synth_good_for_params_all_extended.txt") #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/moog_synth_good_for_params_all_extended.txt") #line_regions_with_atomic_data = ispec.read_line_regions(ispec_dir + "/input/regions/47000_VALD/width_synth_good_for_params_all_extended.txt") smoothed_star_spectrum = ispec.convolve_spectrum(star_spectrum, 2*to_resolution) line_regions_with_atomic_data = ispec.adjust_linemasks(smoothed_star_spectrum, line_regions_with_atomic_data, max_margin=0.5) #telluric_linelist_file = ispec_dir + "/input/linelists/CCF/Synth.Tellurics.500_1100nm/mask.lst" #telluric_linelist = ispec.read_telluric_linelist(telluric_linelist_file, minimum_depth=0.01) #vel_telluric = 17.79 # km/s #telluric_linelist = None #vel_telluric = None #--- Fit the lines but do NOT cross-match with any atomic linelist since they already have that information linemasks = ispec.fit_lines(line_regions_with_atomic_data, normalized_star_spectrum, star_continuum_model, \ atomic_linelist = None, \ max_atomic_wave_diff = 0.005, \ telluric_linelist = telluric_linelist, \ check_derivatives = False, \ vel_telluric = vel_telluric, discard_gaussian=False, \ smoothed_spectrum=None, \ discard_voigt=True, \ free_mu=True, crossmatch_with_mu=False, closest_match=False) # Discard bad masks flux_peak = normalized_star_spectrum['flux'][linemasks['peak']] flux_base = normalized_star_spectrum['flux'][linemasks['base']] flux_top = normalized_star_spectrum['flux'][linemasks['top']] bad_mask = np.logical_or(linemasks['wave_peak'] <= linemasks['wave_base'], linemasks['wave_peak'] >= linemasks['wave_top']) bad_mask = np.logical_or(bad_mask, flux_peak >= flux_base) bad_mask = np.logical_or(bad_mask, flux_peak >= flux_top) linemasks = linemasks[~bad_mask] # Exclude lines with EW equal to zero rejected_by_zero_ew = (linemasks['ew'] == 0) linemasks = linemasks[~rejected_by_zero_ew] # Exclude lines that may be affected by tellurics rejected_by_telluric_line = (linemasks['telluric_wave_peak'] != 0) linemasks = linemasks[~rejected_by_telluric_line] if use_ares: # Replace the measured equivalent widths by the ones computed by ARES old_linemasks = linemasks.copy() ### Different rejection parameters (check ARES papers): ## - http://adsabs.harvard.edu/abs/2007A%26A...469..783S ## - http://adsabs.harvard.edu/abs/2015A%26A...577A..67S #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="0.995", tmp_dir=None, verbose=0) #linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="3;5764,5766,6047,6052,6068,6076", tmp_dir=None, verbose=0) snr = 50 linemasks = ispec.update_ew_with_ares(normalized_star_spectrum, linemasks, rejt="%s" % (snr), tmp_dir=None, verbose=0) self.assertEqual(len(linemasks), 281) self.assertAlmostEqual(linemasks['ew'][0], 68.62459244466727) self.assertAlmostEqual(linemasks['ew'][-3], 46.23135207295078) self.assertEqual(linemasks['element'][0], 'Fe 1') self.assertEqual(linemasks['element'][-3], 'Si 1') self.assertAlmostEqual(linemasks['loggf'][0], -1.028) self.assertAlmostEqual(linemasks['loggf'][-3], -1.062)