示例#1
0
def convolveTelluric(lsf, telluric_data, alpha=1.0, airmass='1.5', pwv='1.5'):
	"""
	Return a convolved telluric transmission model given a telluric data and lsf.
	"""
	# get a telluric standard model
	wavelow               = telluric_data.wave[0]  - 50
	wavehigh              = telluric_data.wave[-1] + 50
	telluric_model        = nsp.getTelluric(wavelow=wavelow,wavehigh=wavehigh, airmass=airmass, pwv=pwv)
	telluric_model.flux **= alpha
	# lsf
	telluric_model.flux = nsp.broaden(wave=telluric_model.wave, flux=telluric_model.flux, 
		vbroad=lsf, rotate=False, gaussian=True)
	# resample
	telluric_model.flux = np.array(nsp.integralResample(xh=telluric_model.wave, 
		yh=telluric_model.flux, xl=telluric_data.wave))
	telluric_model.wave = telluric_data.wave
	return telluric_model
示例#2
0
def applyTelluric(model, alpha=1, airmass='1.5'):
	"""
	Apply the telluric model on the science model.

	Parameters
	----------
	model 	:	model object
				BT Settl model
	alpha 	: 	float
				telluric scaling factor (the power on the flux)

	Returns
	-------
	model 	: 	model object
				BT Settl model times the corresponding model

	"""
	# read in a telluric model
	wavelow  = model.wave[0] - 10
	wavehigh = model.wave[-1] + 10
	telluric_model = nsp.getTelluric(wavelow=wavelow,
		wavehigh=wavehigh, alpha=alpha, airmass=airmass)
	# apply the telluric alpha parameter
	#telluric_model.flux = telluric_model.flux**(alpha)

	#if len(model.wave) > len(telluric_model.wave):
	#	print("The model has a higher resolution ({}) than the telluric model ({})."\
	#		.format(len(model.wave),len(telluric_model.wave)))
	#	model.flux = np.array(nsp.integralResample(xh=model.wave, 
	#		yh=model.flux, xl=telluric_model.wave))
	#	model.wave = telluric_model.wave
	#	model.flux *= telluric_model.flux

	#elif len(model.wave) < len(telluric_model.wave):
	## This should be always true
	telluric_model.flux = np.array(nsp.integralResample(xh=telluric_model.wave, 
		yh=telluric_model.flux, xl=model.wave))
	telluric_model.wave = model.wave
	model.flux *= telluric_model.flux

	#elif len(model.wave) == len(telluric_model.wave):
	#	model.flux *= telluric_model.flux
		
	return model
示例#3
0
def convolveTelluric(lsf, airmass, pwv, telluric_data):
	"""
	Return a convolved telluric transmission model given a telluric data and lsf.
	"""
	# get a telluric standard model
	wavelow               = telluric_data.wave[0]  - 50
	wavehigh              = telluric_data.wave[-1] + 50
	modelwave, modelflux  = InterpTelluricModel(wavelow=wavelow, wavehigh=wavehigh, airmass=airmass, pwv=pwv)
	#modelflux           **= alpha
	# lsf
	modelflux             = nsp.broaden(wave=modelwave, flux=modelflux, vbroad=lsf, rotate=False, gaussian=True)
	# resample
	modelflux             = np.array(nsp.integralResample(xh=modelwave, yh=modelflux, xl=telluric_data.wave))
	modelwave             = telluric_data.wave
	telluric_model        = nsp.Model()
	telluric_model.flux   = modelflux
	telluric_model.wave   = modelwave

	return telluric_model
def makeModel(teff, logg, z, vsini, rv, alpha, wave_offset, flux_offset,
              **kwargs):
    """
	Return a forward model.

	Parameters
	----------
	params : a dictionary that specifies the parameters such as teff, logg, z.
	data   : an input science data used for continuum correction

	Returns
	-------
	model: a synthesized model
	"""

    # read in the parameters
    order = kwargs.get('order', 33)
    modelset = kwargs.get('modelset', 'btsettl08')
    lsf = kwargs.get('lsf', 6.0)  # instrumental LSF
    tell = kwargs.get('tell', True)  # apply telluric
    data = kwargs.get('data', None)  # for continuum correction and resampling

    if data is not None:
        order = data.order
    # read in a model
    #model    = nsp.Model(teff=teff, logg=logg, feh=z, order=order, modelset=modelset)
    model = nsp.Model()
    model.wave, model.flux = InterpModel(teff,
                                         logg,
                                         modelset=modelset,
                                         order=order)
    model.wave *= 10000
    # wavelength offset
    #model.wave += wave_offset

    # apply vsini
    model.flux = nsp.broaden(wave=model.wave,
                             flux=model.flux,
                             vbroad=vsini,
                             rotate=True,
                             gaussian=False)

    # apply rv (including the barycentric correction)
    model.wave = nsp.rvShift(model.wave, rv=rv)

    # apply telluric
    if tell is True:
        model = nsp.applyTelluric(model=model, alpha=alpha, airmass='1.5')
    # NIRSPEC LSF
    model.flux = nsp.broaden(wave=model.wave,
                             flux=model.flux,
                             vbroad=lsf,
                             rotate=False,
                             gaussian=True)

    # add a fringe pattern to the model
    #model.flux *= (1+amp*np.sin(freq*(model.wave-phase)))

    # wavelength offset
    model.wave += wave_offset

    # integral resampling
    if data is not None:
        model.flux = np.array(
            nsp.integralResample(xh=model.wave, yh=model.flux, xl=data.wave))
        model.wave = data.wave
        # contunuum correction
        model = nsp.continuum(data=data, mdl=model)

    # flux offset
    model.flux += flux_offset
    #model.flux **= (1 + flux_exponent_offset)

    return model
# apply rv (including the barycentric correction)
model.wave = nsp.rvShift(model.wave, rv=rv)

model_notell = copy.deepcopy(model)
# apply telluric
model = nsp.applyTelluric(model=model, alpha=alpha)
# NIRSPEC LSF
model.flux = nsp.broaden(wave=model.wave,
                         flux=model.flux,
                         vbroad=lsf,
                         rotate=False,
                         gaussian=True)

# integral resampling
model.flux = np.array(
    nsp.integralResample(xh=model.wave, yh=model.flux, xl=data.wave))
model.wave = data.wave

# contunuum correction
model, cont_factor = nsp.continuum(data=data, mdl=model, prop=True)

# NIRSPEC LSF
model_notell.flux = nsp.broaden(wave=model_notell.wave,
                                flux=model_notell.flux,
                                vbroad=lsf,
                                rotate=False,
                                gaussian=True)

# integral resampling
model_notell.flux = np.array(
    nsp.integralResample(xh=model_notell.wave,
示例#6
0
def makeModel(teff, logg, z, vsini, rv, wave_offset, flux_offset, **kwargs):
    """
	Return a forward model.

	Parameters
	----------
	teff   : effective temperature
	
	data   : an input science data used for continuum correction

	Optional Parameters
	-------------------
	

	Returns
	-------
	model: a synthesized model
	"""

    # read in the parameters
    order = kwargs.get('order', 33)
    modelset = kwargs.get('modelset', 'btsettl08')
    instrument = kwargs.get('instrument', 'nirspec')
    lsf = kwargs.get('lsf', 6.0)  # instrumental LSF
    tell = kwargs.get('tell', True)  # apply telluric
    data = kwargs.get('data', None)  # for continuum correction and resampling

    if data is not None and instrument == 'nirspec':
        order = data.order
        # read in a model
        #print('teff ',teff,'logg ',logg, 'z', z, 'order', order, 'modelset', modelset)
        #print('teff ',type(teff),'logg ',type(logg), 'z', type(z), 'order', type(order), 'modelset', type(modelset))
        model = nsp.Model(teff=teff,
                          logg=logg,
                          feh=z,
                          order=order,
                          modelset=modelset,
                          instrument=instrument)

    elif data is not None and instrument == 'apogee':
        model = nsp.Model(teff=teff,
                          logg=logg,
                          feh=z,
                          modelset=modelset,
                          instrument=instrument)

    # wavelength offset
    #model.wave += wave_offset

    # apply vsini
    model.flux = nsp.broaden(wave=model.wave,
                             flux=model.flux,
                             vbroad=vsini,
                             rotate=True,
                             gaussian=False)

    # apply rv (including the barycentric correction)
    model.wave = nsp.rvShift(model.wave, rv=rv)

    # instrumental LSF
    model.flux = nsp.broaden(wave=model.wave,
                             flux=model.flux,
                             vbroad=lsf,
                             rotate=False,
                             gaussian=True)

    # add a fringe pattern to the model
    #model.flux *= (1+amp*np.sin(freq*(model.wave-phase)))

    # wavelength offset
    model.wave += wave_offset

    # integral resampling
    if data is not None:
        model.flux = np.array(
            nsp.integralResample(xh=model.wave, yh=model.flux, xl=data.wave))
        model.wave = data.wave
        # contunuum correction
        model = nsp.continuum(data=data, mdl=model)

    # flux offset
    model.flux += flux_offset
    #model.flux **= (1 + flux_exponent_offset)

    return model
示例#7
0
def makeModel(teff,logg,z,vsini,rv,alpha,wave_offset,flux_offset,**kwargs):
	"""
	Return a forward model.

	Parameters
	----------
	teff   : effective temperature
	
	data   : an input science data used for continuum correction

	Optional Parameters
	-------------------
	

	Returns
	-------
	model: a synthesized model
	"""

	# read in the parameters
	order      = kwargs.get('order', 33)
	modelset   = kwargs.get('modelset', 'btsettl08')
	instrument = kwargs.get('instrument', 'nirspec')
	lsf        = kwargs.get('lsf', 6.0)   # instrumental LSF
	tell       = kwargs.get('tell', True) # apply telluric
	data       = kwargs.get('data', None) # for continuum correction and resampling
	output_stellar_model = kwargs.get('output_stellar_model', False)
	
	if data is not None and instrument == 'nirspec':
		order = data.order
		# read in a model
		#print('teff ',teff,'logg ',logg, 'z', z, 'order', order, 'modelset', modelset)
		#print('teff ',type(teff),'logg ',type(logg), 'z', type(z), 'order', type(order), 'modelset', type(modelset))
		model    = nsp.Model(teff=teff, logg=logg, feh=z, order=order, modelset=modelset, instrument=instrument)

	#elif data is not None and instrument == 'apogee':
	elif instrument == 'apogee':
		model    = nsp.Model(teff=teff, logg=logg, feh=z, modelset=modelset, instrument=instrument)
	
	elif data is None and instrument == 'nirspec':
		model    = nsp.Model(teff=teff, logg=logg, feh=z, order=order, modelset=modelset, instrument=instrument)
	
	# wavelength offset
	#model.wave += wave_offset

	# apply vsini
	model.flux = nsp.broaden(wave=model.wave, 
		flux=model.flux, vbroad=vsini, rotate=True, gaussian=False)
	
	# apply rv (including the barycentric correction)
	model.wave = rvShift(model.wave, rv=rv)
	
	if output_stellar_model:
		stellar_model = copy.deepcopy(model)
	# apply telluric
	if tell is True:
		model = nsp.applyTelluric(model=model, alpha=alpha, airmass='1.5')
	# instrumental LSF
	model.flux = nsp.broaden(wave=model.wave, 
		flux=model.flux, vbroad=lsf, rotate=False, gaussian=True)

	if output_stellar_model:
		stellar_model.flux = nsp.broaden(wave=stellar_model.wave, 
			flux=stellar_model.flux, vbroad=lsf, rotate=False, gaussian=True)

	# add a fringe pattern to the model
	#model.flux *= (1+amp*np.sin(freq*(model.wave-phase)))

	# wavelength offset
	model.wave += wave_offset

	if output_stellar_model: stellar_model.wave += wave_offset

	# integral resampling
	if data is not None:
		model.flux = np.array(nsp.integralResample(xh=model.wave, 
			yh=model.flux, xl=data.wave))
		model.wave = data.wave

		if output_stellar_model:
			stellar_model.flux = np.array(nsp.integralResample(xh=stellar_model.wave, 
				yh=stellar_model.flux, xl=data.wave))
			stellar_model.wave = data.wave
		# contunuum correction
		if data.instrument == 'nirspec':
			if output_stellar_model:
				model, cont_factor = nsp.continuum(data=data, mdl=model, prop=True)
				stellar_model.flux *= cont_factor
			else:
				model = nsp.continuum(data=data, mdl=model)
		elif data.instrument == 'apogee' and data.datatype =='apvisit':
			## set the order in the continuum fit
			deg         = 5

			## because of the APOGEE bands, continuum is corrected from three pieces of the spectra
			data0       = copy.deepcopy(data)
			model0      = copy.deepcopy(model)

			range0      = np.where((data0.wave >= data.oriWave0[0][-1]) & (data0.wave <= data.oriWave0[0][0]))
			data0.wave  = data0.wave[range0]
			data0.flux  = data0.flux[range0]
			data0.noise = data0.noise[range0]
			model0.wave = model0.wave[range0]
			model0.flux = model0.flux[range0]
			model0      = nsp.continuum(data=data0, mdl=model0, deg=deg)

			data1       = copy.deepcopy(data)
			model1      = copy.deepcopy(model)
			range1      = np.where((data1.wave >= data.oriWave0[1][-1]) & (data1.wave <= data.oriWave0[1][0]))
			data1.wave  = data1.wave[range1]
			data1.flux  = data1.flux[range1]
			data1.noise = data1.noise[range1]
			model1.wave = model1.wave[range1]
			model1.flux = model1.flux[range1]
			model1      = nsp.continuum(data=data1, mdl=model1, deg=deg)

			data2       = copy.deepcopy(data)
			model2      = copy.deepcopy(model)
			range2      = np.where((data2.wave >= data.oriWave0[2][-1]) & (data2.wave <= data.oriWave0[2][0]))
			data2.wave  = data2.wave[range2]
			data2.flux  = data2.flux[range2]
			data2.noise = data2.noise[range2]
			model2.wave = model2.wave[range2]
			model2.flux = model2.flux[range2]
			model2      = nsp.continuum(data=data2, mdl=model2, deg=deg)

			model.flux  = np.array( list(model0.flux) + list(model1.flux) + list(model2.flux) )
			model.wave  = np.array( list(model0.wave) + list(model1.wave) + list(model2.wave) )
		elif data.instrument == 'apogee' and data.datatype =='apstar':
			model = nsp.continuum(data=data, mdl=model)

	# flux offset
	model.flux += flux_offset
	if output_stellar_model: stellar_model.flux += flux_offset
	#model.flux **= (1 + flux_exponent_offset)

	if output_stellar_model:
		return model, stellar_model
	else:
		return model
示例#8
0
def continuumTelluric(data, model=None, order=None):
    """
    Return a continnum telluric standard data.
    Default: return a telluric flux of mean 1.

    Parameters
    ----------
    data:  spectrum object
           The input telluric data to be continuum
           corrected

    model: (optional) model object
           The telluric model to obtain the mean flux
           Instead of 1 as in default, it returns a constant
           shift by the difference between the mean flux of 
           the telluric data and that of the telluric model

    Returns
    -------
    data: spectrum object
          continuum corrected telluric data

    Examples
    --------
    >>> import nirspec_pip as nsp
    >>> nsp.continuumTelluric(data)

    >>> nsp.continuumTelluric(data,model)

    """
    if model is None:
        wavelow = data.wave[0] - 20
        wavehigh = data.wave[-1] + 20
        model = nsp.getTelluric(wavelow, wavehigh)

    if not data.applymask:
        data2 = copy.deepcopy(data)
        data.maskBySigmas(sigma=1.5)
    else:
        data2 = copy.deepcopy(data)
        data.wave = data.wave[10:-30]
        data.flux = data.flux[10:-30]
        data.noise = data.noise[10:-30]

    #    plt.plot(data.wave,data.flux, alpha=0.5)
    #    plt.plot(data2.wave,data2.flux, alpha=0.5)
    #    plt.show()
    #    plt.close()

    if data.order == 35:
        # O35 has a voigt absorption profile
        popt, pcov = curve_fit(
            voigt_profile,
            data.wave[20:-20],
            data.flux[20:-20],
            p0=[21660, 2000, 0.1, 0.1, 0.01, 0.1, 10000, 1000],
            maxfev=10000)
        #plt.plot(data.wave,data.flux,'k-',alpha=0.5)
        #plt.plot(data.wave,voigt_profile(data.wave,*popt),'r-',alpha=0.5)
        #plt.show()
        #plt.close()
        const = np.mean(data.flux/voigt_profile(data.wave, *popt))\
        -np.mean(model.flux)
        data.flux = data.flux / voigt_profile(data.wave, *popt) - const
        data.noise = data.noise / voigt_profile(data.wave, *popt)
        #if not data.applymask:
        data2.flux = data2.flux / voigt_profile(data2.wave, *popt) - const
        data2.noise = data2.noise / voigt_profile(data2.wave, *popt)
        data = data2

    elif data.order == 38 or data.order == 30:
        # O38 has rich absorption features
        def fit_continuum_O38(x, a, b, **kwargs):
            flux = kwargs.get('flux', data.flux)
            linear = a * x + b
            return flux / linear

        model2 = copy.deepcopy(model)
        model2.flux = nsp.broaden(wave=model2.wave,
                                  flux=model2.flux,
                                  vbroad=4.8,
                                  rotate=False,
                                  gaussian=True)
        model2.flux = np.array(
            nsp.integralResample(xh=model2.wave, yh=model2.flux, xl=data.wave))
        model2.wave = data.wave

        popt, pcov = curve_fit(fit_continuum_O38,
                               data.wave,
                               model2.flux,
                               p0=[8.54253062e+00, -166000])
        #const = np.mean(data.flux/linear_fit(data.wave, *popt))-np.mean(model.flux)
        #data.flux = data.flux/linear_fit(data.wave, *popt) - const
        data.flux = data.flux / linear_fit(data.wave, *popt)
        data.noise = data.noise / linear_fit(data.wave, *popt)
        #if not data.applymask:
        data2.flux /= linear_fit(data2.wave, *popt)
        data2.noise /= linear_fit(data2.wave, *popt)
        data = data2

    elif data.order == 55:
        popt, pcov = curve_fit(_continuumFit, data.wave, data.flux)
        #if data.applymask:
        #    data.flux   = data.flux/_continuumFit(data.wave, *popt)
        #    data.noise  = data.noise/_continuumFit(data.wave, *popt)
        #
        #    factor      = np.max(data.flux)
        #    data.flux  /= factor
        #    data.noise /= factor
        #    data.flux  /= 0.93
        #    data.noise /= 0.93

        #elif not data.applymask:
        data2.flux = data2.flux / _continuumFit(data2.wave, *popt)
        data2.noise = data2.noise / _continuumFit(data2.wave, *popt)

        factor = np.max(data2.flux)
        data2.flux = data2.flux / factor
        data2.noise = data2.noise / factor

        data2.flux /= 0.93
        data2.noise /= 0.93

        data = data2

    elif data.order == 56:
        # select the highest points to fit a polynomial
        x1 = np.max(data.flux[0:100])
        x2 = np.max(data.flux[100:150])
        x3 = np.max(data.flux[200:300])
        x4 = np.max(data.flux[300:400])
        x5 = np.max(data.flux[600:700])
        x6 = np.max(data.flux[700:800])

        a = [
            float(data.wave[np.where(data.flux == x1)]),
            float(data.wave[np.where(data.flux == x2)]),
            float(data.wave[np.where(data.flux == x3)]),
            float(data.wave[np.where(data.flux == x4)]),
            float(data.wave[np.where(data.flux == x5)]),
            float(data.wave[np.where(data.flux == x6)])
        ]

        b = [x1, x2, x3, x4, x5, x6]

        popt, pcov = curve_fit(_continuumFit, a, b)

        data.flux = data.flux / _continuumFit(data.wave, *popt) * 0.85
        data.noise = data.noise / _continuumFit(data.wave, *popt) * 0.85
        #if not data.applymask:
        data2.flux = data2.flux / _continuumFit(data2.wave, *popt) * 0.85
        data2.noise = data2.noise / _continuumFit(data2.wave, *popt) * 0.85
        data = data2

    elif data.order == 59:
        #wave0 = int(data.wave[np.where(data.flux==np.min(data.flux))])
        popt, pcov = curve_fit(
            voigt_profile,
            data.wave,
            data.flux,
            p0=[12820, 2000, 0.1, 0.1, 0.01, 0.1, 10000, 1000],
            maxfev=100000)
        #p0=[wave0,2000,0.1,0.1,0.01,0.1,10000,1000],
        #maxfev=10000)
        data.flux /= voigt_profile(data.wave, *popt)
        data.noise /= voigt_profile(data.wave, *popt)
        #if not data.applymask:
        data2.flux /= voigt_profile(data2.wave, *popt)
        data2.noise /= voigt_profile(data2.wave, *popt)
        data = data2
        #plt.plot(data.wave,data.flux)
        #plt.show()
        #plt.close()

    ## this is not true in general!!
    elif data.order == 65:
        # O65 is best mateched by a gaussian absorption feature
        popt, pcov = curve_fit(gaus_absorption_only,
                               data.wave,
                               data.flux,
                               p0=[11660, 50, 2000, 2000],
                               maxfev=100000)
        const = np.mean(
            data.flux / gaus_absorption_only(data.wave, *popt)) - np.mean(
                model.flux)
        data.flux = data.flux / gaus_absorption_only(data.wave, *popt) - const
        data.noise /= gaus_absorption_only(data.wave, *popt)
        #if not data.applymask:
        data2.flux = data2.flux / gaus_absorption_only(data2.wave, *
                                                       popt) - const
        data2.noise /= gaus_absorption_only(data2.wave, *popt)
        data = data2

    else:
        # this second order polynomial continnum correction
        # works for the O33, O34, O36, and O37
        popt, pcov = curve_fit(_continuumFit, data.wave, data.flux)
        const = np.mean(data.flux / _continuumFit(data.wave, *popt)) - np.mean(
            model.flux)
        if data.order == 57: const = 0
        data.flux = data.flux / _continuumFit(data.wave, *popt) - const
        data.noise = data.noise / _continuumFit(data.wave, *popt)
        #if not data.applymask:
        data2.flux = data2.flux / _continuumFit(data2.wave, *popt) - const
        data2.noise = data2.noise / _continuumFit(data2.wave, *popt)
        data = data2

    return data