Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
csst-sims
csst_cpic_sim
Commits
a9528a92
Commit
a9528a92
authored
Apr 15, 2024
by
Chen Yili
Browse files
Upload New File
parent
a8e88b2e
Changes
1
Hide whitespace changes
Inline
Side-by-side
CpicImgSim/target.py
0 → 100644
View file @
a9528a92
import
re
import
json
import
numpy
as
np
from
scipy
import
constants
from
astropy.io
import
fits
from
astropy.coordinates
import
SkyCoord
from
.config
import
cpism_refdata
,
MAG_SYSTEM
from
.config
import
S
# pysynphot
from
.optics
import
filter_throughput
from
.io
import
log
PLANK_H
=
constants
.
h
# ~6.62607015e-34
LIGHT_SPEED
=
constants
.
c
# ~3e8
DEG2RAD
=
np
.
pi
/
180
R_JUPITER_METER
=
6.99e4
AU_METER
=
1.49e8
DEFAULT_FILTER_FILE
=
f
'
{
cpism_refdata
}
/throughtput/f661_total.fits'
HYBRID_MODEL_FILE
=
f
'
{
cpism_refdata
}
/target_model/hybrid_model.fits'
def
_sptype2num
(
spectral_type
):
"""
convert spectral type string to number, for interpretation
case0: normal case
- M1V: 6.1, 5
- O5IV: 0.5, 4
- F3V: 3.3, 5
- K4.5II: 5.45, 2
case 1: star type or subtype missing
zero or V will return
- M1: 6.1, 5
- M: 6.0, 5
case 2: spectral type + subtype
subtype will be ignored
- K3Vvar: 5.3, 5
- F6Vbwvar: 3.6, 5
- K0IV SB: 5.0, 4
- F5V+: 3.5, 5
case 3: multi spectral type
only the first sptype is used
- G5IV/V +K1IV: 4.5, 4
- F7IV-V: 3.7, 4
- O4/O5IV: 0.4, 0
- G3/G5V: 4.3, 0
case 4: illegal input
ValueError will be raised
"""
obafgkm
=
'OBAFGKML'
spectral_type
=
spectral_type
.
upper
()
# match spectral type such as M1V, O5IV, F3V, K4.5II
matched
=
re
.
match
(
RF
'^([
{
obafgkm
}
])([0-9]\d*\.?\d*)*([IV]*)'
,
spectral_type
)
if
not
matched
:
raise
ValueError
(
f
"illegal spectral type input:
{
spectral_type
}
"
)
shorttype
=
obafgkm
.
find
(
matched
.
group
(
1
))
subtype
=
0.0
if
matched
.
group
(
2
):
subtype
=
float
(
matched
.
group
(
2
))
stlist
=
[
'O'
,
'I'
,
'II'
,
'III'
,
'IV'
,
'V'
]
startype
=
dict
(
zip
(
stlist
,
range
(
len
(
stlist
)))).
get
(
matched
.
group
(
3
),
5
)
return
shorttype
+
subtype
/
10
,
startype
def
_spnum2teff
(
spn
,
stn
):
"""
interpret of spectral number (by __sptype2num) to get t_eff and log_g
look up table from the document of ck04model
"""
with
open
(
f
'
{
cpism_refdata
}
/target_model/sptype2teff_lut.json'
,
'r'
)
as
fid
:
sptype_teff_lut
=
json
.
load
(
fid
)
def
_interp
(
spn
,
stn
):
lut
=
sptype_teff_lut
[
f
'
{
stn
}
'
]
teff
=
np
.
interp
(
spn
,
lut
[
0
],
lut
[
1
])
logg
=
np
.
interp
(
spn
,
lut
[
0
],
lut
[
2
])
return
teff
,
logg
stn
=
5
if
stn
not
in
[
1
,
2
,
3
,
4
,
5
]
else
stn
if
stn
in
[
1
,
3
,
5
]:
return
_interp
(
spn
,
stn
)
else
:
teff_low
,
logg_low
=
_interp
(
spn
,
stn
-
1
)
teff_high
,
logg_high
=
_interp
(
spn
,
stn
+
1
)
return
(
teff_high
+
teff_low
)
/
2
,
(
logg_high
+
logg_low
)
/
2
def
star_photlam
(
magnitude
:
float
,
sptype
:
str
,
is_blackbody
:
bool
=
False
,
mag_input_band
:
str
=
'f661'
):
"""
genrate flux spectrum of a star by its observal magnitude and spectral type
Parameters
----------
magnitude: float
magnitude of the star
sptype: str
spectral type of the star
is_blackbody: bool
if True, use blackbody spectrum instead of ck04model
mag_input_band: str
bandpass of the input magnitude, default is f661
Returns
-------
pysynphot.spectrum.ArraySpectrum
spectrum of the star in photlam unit
"""
spn
,
stn
=
_sptype2num
(
sptype
)
t_eff
,
log_g
=
_spnum2teff
(
spn
,
stn
)
log
.
debug
(
f
"
{
sptype
}
star => [
{
t_eff
=
:}
,
{
log_g
=
:}
];
{
is_blackbody
=
:}
"
)
filter
=
filter_throughput
(
mag_input_band
)
if
not
is_blackbody
:
METALLICITY
=
0
spectrum
=
S
.
Icat
(
'ck04models'
,
t_eff
,
METALLICITY
,
log_g
)
else
:
spectrum
=
S
.
BlackBody
(
t_eff
)
star_sp
=
spectrum
.
renorm
(
magnitude
,
MAG_SYSTEM
,
filter
)
star_sp
.
convert
(
'photlam'
)
return
star_sp
def
hybrid_albedo_spectrum
(
coe_b
:
float
,
coe_r
:
float
):
"""
albedo spectrum of planet using hybrid-jupiter-neptune model (Lacy et al. 2018)
jupiter and neptune spectrum is from Karkoschka’s 1994
Parameters
----------
coe_b: float
coefficient of blue spectrum, 1 for jupiter, 0 for neptune
coe_r: float
coefficient of red spectrum, 1 for jupiter, 0 for neptune
Returns
-------
pysynphot.spectrum.ArrayBandpass
albedo spectrum of the planet
"""
log
.
debug
(
f
"planet hybrid spectrum with
{
coe_b
=
:}
,
{
coe_r
=
:}
"
)
model
=
fits
.
getdata
(
HYBRID_MODEL_FILE
)
spec
=
model
[
1
,
:]
*
coe_r
spec
+=
model
[
2
,
:]
*
coe_b
spec
+=
model
[
3
,
:]
*
(
1
-
coe_r
)
spec
+=
model
[
4
,
:]
*
(
1
-
coe_b
)
albedo
=
S
.
ArrayBandpass
(
wave
=
model
[
0
,
:],
throughput
=
spec
,
waveunits
=
'nm'
)
albedo
.
convert
(
'angstrom'
)
return
albedo
def
extract_target_x_y
(
target
:
dict
,
ra0
:
str
=
None
,
dec0
:
str
=
None
):
"""
extract x, y of target from target dict
Parameters
----------
target: dict
target dict. must contain either (ra, dec) or (pangle, spearation)
ra0: str
ra of center star. must be provided if (ra, dec) of target is used
dec0: str
dec of center star. must be provided if (ra, dec) of target is used
Returns
-------
x, y: float
x, y of target in arcsec
Raises
------
ValueError
if (ra, dec) of target is used but (ra, dec) of center star is not provided.
ValueError
one of (ra, dec) or (pangle, spearation) is not provided.
"""
def
_pa2xy
(
p_angle
,
separation
):
p_angle_rad
=
p_angle
*
DEG2RAD
x
=
separation
*
np
.
sin
(
p_angle_rad
)
y
=
separation
*
np
.
cos
(
p_angle_rad
)
log
.
debug
(
f
"(
{
p_angle
=
:}
,
{
separation
=
:}
) => (
{
x
=
:}
,
{
y
=
:}
)"
)
return
x
,
y
if
'pangle'
in
target
.
keys
()
and
'separation'
in
target
.
keys
():
return
_pa2xy
(
target
[
'pangle'
],
target
[
'separation'
])
if
'ra'
not
in
target
.
keys
()
or
'dec'
not
in
target
.
keys
():
raise
ValueError
(
'either (ra, dec) or (pangle, separation) needed in target dict'
)
if
ra0
is
None
or
dec0
is
None
:
raise
ValueError
(
'(ra, dec) of center star must be provided if (ra, dec) of bkstar is used'
)
ra
,
dec
=
target
[
'ra'
],
target
[
'dec'
]
log
.
debug
(
f
"target:
{
ra
=
:}
,
{
dec
=
:}
, center star:
{
ra0
=
:}
,
{
dec0
=
:}
"
)
cstar
=
SkyCoord
(
ra0
,
dec0
)
bkstar
=
SkyCoord
(
ra
,
dec
)
separation
=
cstar
.
separation
(
bkstar
).
arcsec
p_angle
=
cstar
.
position_angle
(
bkstar
).
degree
x
,
y
=
_pa2xy
(
p_angle
,
separation
)
return
x
,
y
def
planet_contrast
(
planet_x_au
:
float
,
planet_y_au
:
float
,
phase_angle
:
float
,
radius
:
float
):
"""
calculate the contrast of a planet
Parameters
----------
planet_x_au: float
x position of the planet in au
planet_y_au: float
y position of the planet in au
phase_angle: float
phase angle of the planet in degree
radius: float
radius of the planet in jupiter radius
Returns
-------
contrast: float
contrast of the planet
"""
separation
=
np
.
sqrt
(
planet_x_au
**
2
+
planet_y_au
**
2
)
phase_angle
=
phase_angle
*
DEG2RAD
if
np
.
sin
(
phase_angle
)
<
1e-9
:
raise
ValueError
(
'sin(phase_angle) can not be 0'
)
sep_3d
=
separation
/
np
.
sin
(
phase_angle
)
# Lambert Scattering phase function
# from Madhusudhan and Burrows 2012 equation 33.
phase
=
(
np
.
sin
(
phase_angle
)
+
(
np
.
pi
-
phase_angle
)
*
np
.
cos
(
phase_angle
))
/
np
.
pi
log
.
debug
(
f
'alpha:
{
phase_angle
/
np
.
pi
*
180
}
{
phase
=
}
'
)
contrast
=
(
radius
/
sep_3d
*
R_JUPITER_METER
/
AU_METER
)
**
2
*
phase
return
contrast
def
spectrum_generator
(
targets
:
dict
):
"""
generate the spectrum due to the input target list
Parameters
----------
targets: dict
target dictionary which contains keyword 'cstar' (necessary), 'stars'(optional), 'planets' (optional).
The values are:
- cstar: dict
- center star information. must contain keywords ra, dec, distance, magnitude, sptype
- stars: list of dict, optional
- list of background stars. each dict must contain ra, dec, magnitude, sptype
- planets: list of dict, optional
- list of planets. each dict must contain pangle, separation, magnitude, radius
Returns
-------
obj_sp_list: list
list of [x, y, spectrum] of each target
Examples
--------
>>> targets = {
... target = {
... 'name': 'TEST1',
... 'cstar': {
... 'magnitude': 0,
... 'ra': '120d',
... 'dec': '40d',
... 'distance': 10,
... 'sptype': 'G0III',
... },
... 'stars': [
... {
... 'magnitude': 15,
... 'ra': '120.001d',
... 'dec': '40.001d',
... 'sptype': 'F0III',
... 'isblackbody': True
... },
... {
... 'magnitude': 10,
... 'pangle': -60,
... 'separation': 2,
... 'sptype': 'A2.5II',
... 'isblackbody': False
... },
...
... ],
... 'planets': [
... {
... 'radius': 2,
... 'pangle': 60,
... 'coe_b': 0.3,
... 'coe_r': 0.7,
... 'separation': 0.5,
... 'phase_angle': 90,
... }
... ]
... }
>>> spectrum_generator(targets)
"""
cstar
=
targets
[
'cstar'
]
stars
=
targets
.
get
(
'stars'
,
[])
planets
=
targets
.
get
(
'planets'
,
[])
obj_sp_list
=
[]
cstar_spectrum
=
star_photlam
(
cstar
[
'magnitude'
],
cstar
[
'sptype'
],
is_blackbody
=
cstar
.
get
(
'isblackbody'
,
False
),
mag_input_band
=
cstar
.
get
(
'mag_input_band'
,
'f661'
)
)
cstar_ra
=
cstar
[
'ra'
]
cstar_dec
=
cstar
[
'dec'
]
cstar_dist
=
cstar
[
'distance'
]
obj_sp_list
.
append
([
0
,
0
,
cstar_spectrum
])
for
star
in
stars
:
star_x
,
star_y
=
extract_target_x_y
(
star
,
cstar_ra
,
cstar_dec
)
spectrum
=
star_photlam
(
star
[
'magnitude'
],
star
[
'sptype'
],
is_blackbody
=
star
.
get
(
'isblackbody'
,
False
),
mag_input_band
=
cstar
.
get
(
'mag_input_band'
,
'f661'
)
)
obj_sp_list
.
append
([
star_x
,
star_y
,
spectrum
])
for
planet
in
planets
:
planet_x
,
planet_y
=
extract_target_x_y
(
planet
)
# angle between observation direction and star-planet direction
phase_angle
=
planet
.
get
(
'phase_angle'
,
90
)
radius
=
planet
.
get
(
'radius'
,
1
)
contrast
=
planet_contrast
(
planet_x
*
cstar_dist
,
planet_y
*
cstar_dist
,
phase_angle
,
radius
,
)
coe_blue
,
coe_red
=
planet
.
get
(
'coe_b'
,
1
),
planet
.
get
(
'coe_r'
,
1
)
albedo_spect
=
hybrid_albedo_spectrum
(
coe_blue
,
coe_red
)
spectrum
=
albedo_spect
*
cstar_spectrum
*
contrast
obj_sp_list
.
append
([
planet_x
,
planet_y
,
spectrum
])
return
obj_sp_list
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment