sed.py 7.46 KB
Newer Older
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/env python
# -*- coding:utf-8 -*-

# @Author: Shuai Feng (hebtu.edu.cn)
# @Time:   2022-09-25

import numpy as np
from scipy.interpolate import interp1d
from astropy.io import fits
from astropy.io import ascii
from astropy import units as u

# ----------------
# Magnitude Module

from scipy.interpolate import interp1d

def Calzetti_Law(wave, Rv = 4.05):
    """Dust Extinction Curve by Calzetti et al. (2000)

    Args:
        wave (float): Wavelength
        Rv (float, optional): Extinction curve. Defaults to 4.05.

    Returns:
        float: Extinction value E(B-V)
    """
    
    wave_number = 1./(wave * 1e-4)
    reddening_curve = np.zeros(len(wave))
    
    idx = np.logical_and(wave >= 1200, wave <= 6300)
    reddening_curve[idx] = 2.659 * ( -2.156 + 1.509 * wave_number[idx] - 0.198 * \
                    (wave_number[idx] ** 2)) + 0.011 * (wave_number[idx] **3 ) + Rv
                                    
    idx = np.logical_and(wave >= 6300, wave <= 22000)
    reddening_curve[idx] = 2.659 * ( -1.857 + 1.040 * wave_number[idx]) + Rv
    return reddening_curve

def reddening(wave, flux, ebv = 0.0, law = 'calzetti', Rv = 4.05):
    """
    Reddening an input spectra through a given reddening curve.

    Args:
        wave (float): Wavelength of input spectra
        flux (float): Flux of input spectra
        ebv (float, optional): Extinction value. Defaults to 0.
        law (str, optional): Extinction curve. Defaults to 'calzetti'.
        Rv (float, optional): _description_. Defaults to 4.05.

    Returns:
        float: Flux of spectra after reddening.
    """
    if law == 'calzetti':
        curve = Calzetti_Law(wave, Rv = Rv)
        fluxNew = flux / (10. ** (0.4 * ebv * curve))
    return fluxNew

Yan Zhaojun's avatar
test    
Yan Zhaojun committed
59
def flux_to_mag(wave, flux, path, band='GAIA_bp'):
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
60
61
62
63
64
65
66
67
68
69
70
    """Convert flux of given spectra to magnitude

    Args:
        wave (float): Wavelength
        flux (float): Flux of spectra
        band (str, optional): Filter band name. Defaults to 'GAIA_bp'.

    Returns:
        float: value of magnitude
    """
    # /home/yan/MCI_sim/MCI_input/SED_Code/data
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
71
    ##import os
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
72
    
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
73
    ###parent = os.path.dirname(os.path.realpath(__file__))
Yan Zhaojun's avatar
update    
Yan Zhaojun committed
74
        
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
75
    band = ascii.read(path+'MCI_inputData/SED_Code/seddata/' + band + '.dat')
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    wave0= band['col1']
    curv0= band['col2']
    
    # Setting the response
    func = interp1d(wave0, curv0)
    response = np.copy(wave)
    ind_extra = (wave > max(wave0)) | (wave < min(wave0))
    response[ind_extra] = 0
    ind_inside = (wave < max(wave0)) & (wave > min(wave0))
    response[ind_inside] = func(wave[ind_inside])

    # Total Flux
    Tflux = np.trapz(flux * response, wave) / np.trapz(response, wave)
    
    return -2.5 * np.log10(Tflux)

Yan Zhaojun's avatar
test    
Yan Zhaojun committed
92
def calibrate(wave, flux, mag, path,band='GAIA_bp'):
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
93
94
95
96
97
98
99
100
101
102
103
104
    """
    Calibrate the spectra according to the magnitude.

    Args:
        wave (float): Wavelength
        flux (float): Flux of spectra
        mag (float): Input magnitude.
        band (str, optional): Filter band name. Defaults to 'GAIA_bp'.

    Returns:
        float: Flux of calibrated spectra. Units: 1e-17 erg/s/A/cm^2
    """
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
105
    inst_mag = flux_to_mag(wave, flux, path,band = band)
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
    instflux = 10 ** (-0.4 * inst_mag)
    realflux = (mag * u.STmag).to(u.erg/u.s/u.cm**2/u.AA).value

    # Normalization
    flux_ratio = realflux / instflux
    flux_calibrate = flux * flux_ratio * 1e17                        # Units: 10^-17 erg/s/A/cm^2
    
    return flux_calibrate

# ------------
# SED Template

class Gal_Temp():
    """
    Template of Galaxy SED
    """
    
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
123
    def __init__(self,path):
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
124
        
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
125
        ###import os
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
126
        
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
127
        ###parent = os.path.dirname(os.path.realpath(__file__))
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
128
129
        self.path=path
        hdulist = fits.open(self.path+'MCI_inputData/SED_Code/seddata/galaxy_temp.fits')
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
130
131
132
133
134
135
136
137
138
139
140
141
        self.wave = hdulist[1].data['wave']
        self.flux = hdulist[2].data
        self.age_grid = hdulist[3].data['logAge']
        self.feh_grid = hdulist[3].data['FeH']
        
    def toMag(self, redshift = 0):
        """Calculating magnitude

        Args:
            redshift (float, optional): redshift of spectra. Defaults to 0.
        """
        wave = self.wave * (1 + redshift)
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
142
143
144
145
146
        self.umag = flux_to_mag(wave, self.flux, self.path,band='SDSS_u')
        self.gmag = flux_to_mag(wave, self.flux, self.path,band='SDSS_g')
        self.rmag = flux_to_mag(wave, self.flux, self.path,band='SDSS_r')
        self.imag = flux_to_mag(wave, self.flux, self.path,band='SDSS_i')
        self.zmag = flux_to_mag(wave, self.flux, self.path,band='SDSS_z')
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
147
148
149
150
151
152
        
class Star_Temp():
    """
    Template of Stellar SED
    """
    
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
153
    def __init__(self,path):
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
154
        
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
155
        ##import os
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
156
        self.path=path
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
157
        ####parent = os.path.dirname(os.path.realpath(__file__))
Yan Zhaojun's avatar
update    
Yan Zhaojun committed
158
        ###print("获取其父目录——" + parent)  # 从当前文件路径中获取目录
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
159
        
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
160
        hdulist = fits.open(path+'MCI_inputData/SED_Code/seddata/stellar_temp.fits')
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
161
162
163
164
165
        self.wave = hdulist[1].data['wave']
        self.flux = hdulist[2].data
        self.Teff_grid = hdulist[3].data['Teff']
        self.FeH_grid = hdulist[3].data['FeH']
        
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
166
167
        self.bpmag = flux_to_mag(self.wave, self.flux, path,band='GAIA_bp')
        self.rpmag = flux_to_mag(self.wave, self.flux, path,band='GAIA_rp')
Yan Zhaojun's avatar
update    
Yan Zhaojun committed
168
169
        
        
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
170
171
    def toMag(self):
        wave = self.wave
Yan Zhaojun's avatar
test    
Yan Zhaojun committed
172
173
        self.bpmag = flux_to_mag(wave, self.flux, self.path,band='GAIA_bp')
        self.rpmag = flux_to_mag(wave, self.flux, self.path,band='GAIA_rp')
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
174
175
176
177
        
# -------------
# SED Modelling

Yan Zhaojun's avatar
update    
Yan Zhaojun committed
178
def Model_Stellar_SED(wave, bp, rp, temp):
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    """Modelling stellar SED based on bp, rp magnitude

    Args:
        wave (float): Wavelength
        bp (float): Magnitude of GAIA BP band
        rp (float): Magnitude of GAIA RP band
        temp (class): Class of stellar template

    Returns:
        float array: Spectral energy distribution of stellar SED, 
        which have the same length to the input wave
    """

    color0 = bp - rp
    colors = temp.bpmag - temp.rpmag
    
    idx = np.argmin(np.abs(colors - color0))
    flux0 = temp.flux[idx]
    flux1 = np.interp(wave, temp.wave, flux0)
Yan Zhaojun's avatar
update    
Yan Zhaojun committed
198
    flux  = calibrate(wave, flux1, rp, band = 'GAIA_rp')
chenwei@shao.ac.cn's avatar
build  
chenwei@shao.ac.cn committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    return flux

def Model_Galaxy_SED(wave, ugriz, z, temp):
    """Modelling galaxy SED based on u,g,r,i,z magnitude

    Args:
        wave (float): Wavelength
        ugriz (float, array): The array of magnitude of SDSS ugriz band
        z (float): Redshift
        temp (class): Class of gaalxy template

    Returns:
        float array: Spectral energy distribution of stellar SED, 
        which have the same length to the input wave
    """
    sed = 10. ** (-0.4 * ugriz)
    sed = sed / sed[2]
    ntemp = len(temp.rmag)
    dmag  = np.zeros(ntemp)
    for j in range(ntemp):
        ugriz0 = np.array([temp.umag[j], temp.gmag[j], temp.rmag[j], 
                           temp.imag[j], temp.zmag[j]])
        sed0 = 10. ** (-0.4 * ugriz0)
        sed0 = sed0 / sed0[2]
        dmag[j] = np.sum(np.abs(sed - sed0))
    
    idx = np.argmin(dmag)
    flux0 = temp.flux[idx]
    
    # Effect of E(B-V)
    ri0 = ugriz[2] - ugriz[3]
    ri  = temp.rmag - temp.imag
    dri = ri0 - ri[idx]
    Alambda = Calzetti_Law(np.array([6213 / (1 + z), 7625 / (1 + z)]))
    eri0 = (Alambda[0] - Alambda[1])
    ebv = dri/eri0
    if ebv<0:
        ebv=0
    if ebv>0.5:
        ebv=0.5
    flux1 = reddening(temp.wave, flux0, ebv = ebv)
    
    flux2 = np.interp(wave, temp.wave * (1 + z), flux1)
    flux  = calibrate(wave, flux2, ugriz[2], band = 'SDSS_r')
    return flux