Demo of spectroscopy mode with slit and prism features
[1]:
from corgisim import scene, instrument, outputs
import matplotlib.pyplot as plt
import numpy as np
import roman_preflight_proper
import proper
from synphot import SourceSpectrum
from synphot.models import Empirical1D
import astropy.units as u
/home/snoiret/Documents/Corgisim/.envCorgisim/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
[2]:
### Copy the default prescription file
roman_preflight_proper.copy_here()
1. Configure scene
Set coronagraph mode and DM/contrast setting
[3]:
cgi_mode = 'spec'
cor_type = 'spc-spec_band3'
dm_case = '2e-8' # '1e-9' case also available
Stellar parameters
[4]:
# --- Host Star Properties ---
Vmag = 5.0 # V-band magnitude of the host star
sptype = 'A3V' # Spectral type of the host star
ref_flag = False # if the target is a reference star or not, default is False
host_star_properties = {'Vmag': Vmag,
'spectral_type': sptype,
'magtype': 'vegamag',
'ref_flag': False}
# --- Build stellar spectrum via a star-only scene ---
_star_scene = scene.Scene(host_star_properties, [])
sp_star = _star_scene.stellar_spectrum
Adding 0 off-axis sources
[5]:
wave_star_nm = sp_star.waveset.to(u.nm)
flux_star = sp_star(sp_star.waveset)
band3_wavel_start, band3_wavel_stop = 669, 791 # for plot limits
band3_axis_start, band3_axis_stop = 650, 810
# Mask to the plot wavelength range for y-axis scaling
mask_star = (wave_star_nm.value >= band3_axis_start) & (wave_star_nm.value <= band3_axis_stop)
fig, ax = plt.subplots(figsize=(10, 4))
ax.axvspan(band3_wavel_start, band3_wavel_stop, alpha=0.2, color='skyblue', label='Band 3 filter')
ax.plot(wave_star_nm, flux_star)
ax.set_xlabel('Wavelength (nm)')
ax.set_ylabel('Flux (PHOTLAM)')
ax.set_title(f'Stellar spectrum (Vmag={Vmag}, {sptype})')
ax.set_xlim(band3_axis_start, band3_axis_stop)
ax.set_ylim(flux_star[mask_star].value.min(), flux_star[mask_star].value.max())
ax.grid(True)
ax.legend()
plt.tight_layout()
plt.show()
Planet parameters
[6]:
Vmag_planet_scene = 27.0
# --- Load companion emission model ---
wave_um, flux = np.loadtxt('HIP99770b_bestfit_R=1000.csv', unpack=True, delimiter=',', skiprows=1)
wave_nm = wave_um*1000
sp_planet = SourceSpectrum(
Empirical1D,
points=wave_nm * u.nm,
lookup_table=flux * u.W / (u.m**2 * u.micron)
)
[7]:
# Define their positions relative to the host star, in milliarcseconds (mas)
# For reference: 1 λ/D at 550 nm with a 2.3 m telescope is ~49.3 mas
mas_per_lamD = 63.72 # Band 3
dx = -2.0 * mas_per_lamD # X position in mas
dy = +6.0 * mas_per_lamD # Y position in mas
point_source_info = [
{
'Vmag': Vmag_planet_scene, # Ignored when Custom_Spectrum is defined, unless Rescale_Custom_Spectrum is True
'magtype': 'vegamag', # Ignored when Custom_Spectrum is defined, unless Rescale_Custom_Spectrum is True
'position_x': dx,
'position_y': dy,
'Custom_Spectrum': sp_planet, # Planet spectrum model
'Rescale_Custom_Spectrum': True # Rescale the planet spectrum to match Vmag
}
]
# --- Create the Astrophysical Scene ---
# This Scene object combines the host star and companion(s)
base_scene = scene.Scene(host_star_properties, point_source_info)
# --- Access the generated stellar spectrum ---
sp_star = base_scene.stellar_spectrum
# --- Access the generated companion spectrum ---
sp_comp = base_scene.off_axis_source_spectrum[0]
Adding 1 off-axis sources
Plot the spectrum in flux ratio units before and after scaling the planet model
[8]:
# --- Plot planet-to-star flux ratio ---
wave_grid_nm = sp_star.waveset.to(u.nm)
flux_comp_vals = sp_comp(sp_star.waveset)
flux_star_vals = sp_star(sp_star.waveset)
fp_fs_scene = flux_comp_vals / flux_star_vals
# Original (unscaled) planet model flux ratio
fp_fs_original = sp_planet(sp_star.waveset) / flux_star_vals
# Mask to the plot wavelength range for y-axis scaling
mask_fpfs = (wave_grid_nm.value >= band3_wavel_start) & (wave_grid_nm.value <= band3_wavel_stop)
scene_mean_fluxratio = np.mean(fp_fs_scene[mask_fpfs])
original_mean_fluxratio = np.mean(fp_fs_original[mask_fpfs])
fig, ax = plt.subplots(figsize=(10, 4))
ax.axvspan(band3_wavel_start, band3_wavel_stop, alpha=0.2, color='skyblue', label='Band 3 filter')
ax.plot(wave_grid_nm, fp_fs_original, label=f'original model; mean flux ratio {original_mean_fluxratio:.1E}')
ax.plot(wave_grid_nm, fp_fs_scene, label=f'scaled spectrum for scene; mean flux ratio {scene_mean_fluxratio:.1E}, Vmag={Vmag_planet_scene:.1f}')
ax.set_xlabel('Wavelength (nm)')
ax.set_ylabel(r'$F_p / F_s$')
ax.set_title(f'Planet-to-star flux ratio')
ax.set_xlim(band3_axis_start, band3_axis_stop)
ax.set_ylim(0, max(fp_fs_scene[mask_fpfs].value.max(), fp_fs_original[mask_fpfs].value.max()))
ax.grid(True)
ax.legend()
plt.tight_layout()
plt.show()
/home/snoiret/Documents/Corgisim/.envCorgisim/lib/python3.12/site-packages/astropy/units/quantity.py:658: RuntimeWarning: divide by zero encountered in divide
result = super().__array_ufunc__(function, method, *arrays, **kwargs)
2. Unocculted star images
Sub-band filters, with prism, no slit
Broadband, with prism, with and without slit
Sub-band prism images, repeated with CFAM filters 3A, 3B, 3C, 3D, 3E, and 3F
[9]:
## Define the polaxis parameter. Use 10 for non-polaxis cases only, as other options are not yet implemented.
polaxis = 10
# output_dim define the size of the output image
output_dim = 121
overfac = 3 # Increase this to 5 for higher accuracy
source_x_offset = base_scene.point_source_dra[0] / mas_per_lamD # FSM offset for prism image of star in lam/D units
source_y_offset = base_scene.point_source_ddec[0] / mas_per_lamD # FSM offset for prism image of star in lam/D units
dm1 = proper.prop_fits_read( roman_preflight_proper.lib_dir + '/examples/spc-spec_ni_' + dm_case + '_dm1_v.fits' )
dm2 = proper.prop_fits_read( roman_preflight_proper.lib_dir + '/examples/spc-spec_ni_' + dm_case + '_dm2_v.fits' )
#set use_fpm keyword to 0 to generate unocculted star image with no FPM
#set prism keyword to PRISM3 to use band 3 spec prism
#supported prism parameters are PRISM2 for band 2 and PRISM3 for band 3
offset_star_optics_keywords = {
'cor_type':cor_type, 'use_errors':0, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':1, 'dm1_v':dm1, 'use_dm2':1, 'dm2_v':dm2, 'use_fpm':0, 'use_lyot_stop':1,
'fsm_x_offset':source_x_offset, 'fsm_y_offset':source_y_offset,
'prism':'PRISM3', 'wav_step_um':2E-3
}
#set bandpass from 3A to 3F to generate image with each CFAM filter
optics_noslit_prism_cfam3A = instrument.CorgiOptics(cgi_mode, bandpass='3A', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_noslit_prism_cfam3B = instrument.CorgiOptics(cgi_mode, bandpass='3B', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_noslit_prism_cfam3C = instrument.CorgiOptics(cgi_mode, bandpass='3C', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_noslit_prism_cfam3D = instrument.CorgiOptics(cgi_mode, bandpass='3D', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_noslit_prism_cfam3E = instrument.CorgiOptics(cgi_mode, bandpass='3E', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_noslit_prism_cfam3F = instrument.CorgiOptics(cgi_mode, bandpass='3F', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
Compute the PSF for the occulted star
[10]:
sim_unocc_noslit_prism_cfam3A = optics_noslit_prism_cfam3A.get_host_star_psf(base_scene)
sim_unocc_noslit_prism_cfam3B = optics_noslit_prism_cfam3B.get_host_star_psf(base_scene)
sim_unocc_noslit_prism_cfam3C = optics_noslit_prism_cfam3C.get_host_star_psf(base_scene)
sim_unocc_noslit_prism_cfam3D = optics_noslit_prism_cfam3D.get_host_star_psf(base_scene)
sim_unocc_noslit_prism_cfam3E = optics_noslit_prism_cfam3E.get_host_star_psf(base_scene)
sim_unocc_noslit_prism_cfam3F = optics_noslit_prism_cfam3F.get_host_star_psf(base_scene)
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 59.890, 81.145
full frame source location (x, y) with prism = 1599.890, 546.145
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 59.945, 70.537
full frame source location (x, y) with prism = 1599.945, 535.537
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 59.994, 61.145
full frame source location (x, y) with prism = 1599.994, 526.145
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.044, 51.460
full frame source location (x, y) with prism = 1600.044, 516.460
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.083, 44.023
full frame source location (x, y) with prism = 1600.083, 509.023
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.000, 60.001
full frame source location (x, y) with prism = 1600.000, 525.001
Store the image array for each filter case
[11]:
image_unocc_noslit_prism_cfam3A = sim_unocc_noslit_prism_cfam3A.host_star_image.data
image_unocc_noslit_prism_cfam3B = sim_unocc_noslit_prism_cfam3B.host_star_image.data
image_unocc_noslit_prism_cfam3C = sim_unocc_noslit_prism_cfam3C.host_star_image.data
image_unocc_noslit_prism_cfam3D = sim_unocc_noslit_prism_cfam3D.host_star_image.data
image_unocc_noslit_prism_cfam3E = sim_unocc_noslit_prism_cfam3E.host_star_image.data
image_unocc_noslit_prism_cfam3F = sim_unocc_noslit_prism_cfam3F.host_star_image.data
Plot the sub-band filter prism images
[12]:
fig = plt.figure(figsize=(20,6))
plt.subplots_adjust(wspace=0.15)
xcrop = 45
plt.subplot(151)
plt.imshow(image_unocc_noslit_prism_cfam3A[xcrop:,xcrop:-xcrop],origin='lower')
plt.title('CFAM 3A, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(152)
plt.imshow(image_unocc_noslit_prism_cfam3B[xcrop:,xcrop:-xcrop],origin='lower')
plt.title('CFAM 3B, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(153)
plt.imshow(image_unocc_noslit_prism_cfam3C[xcrop:,xcrop:-xcrop],origin='lower')
plt.title('CFAM 3C, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(154)
plt.imshow(image_unocc_noslit_prism_cfam3D[xcrop:,xcrop:-xcrop],origin='lower')
plt.title('CFAM 3D, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(155)
plt.imshow(image_unocc_noslit_prism_cfam3E[xcrop:,xcrop:-xcrop],origin='lower')
plt.title('CFAM 3E, PRISM3')
plt.colorbar(shrink=0.5)
[12]:
<matplotlib.colorbar.Colorbar at 0x78d8459aa000>
Broadband and narrowband prism images with slit
Set the optics configuration with the FSAM slit mask. Here we specify the R1C2 slit offset by 6.0 lambda/D.
[13]:
## Define the polaxis parameter. Use 10 for non-polaxis cases only, as other options are not yet implemented.
polaxis = 10
# output_dim define the size of the output image
output_dim = 121
overfac = 3 # Increase this to 5 for higher accuracy
source_x_offset = base_scene.point_source_dra[0] / mas_per_lamD # FSM offset for prism image of star in lam/D units
source_y_offset = base_scene.point_source_ddec[0] / mas_per_lamD # FSM offset for prism image of star in lam/D units
#set slit keyword to R1C2
#supported slits in band 2 are R6C5 and R3C1
#supported slits in band 3 are R1C2 and R3C1
offset_star_optics_keywords ={'cor_type':cor_type, 'use_errors':0, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':1, 'dm1_v':dm1, 'use_dm2':1, 'dm2_v':dm2, 'use_fpm':0, 'use_lyot_stop':1,
'fsm_x_offset':source_x_offset, 'fsm_y_offset':source_y_offset,
'prism':'PRISM3', 'wav_step_um':2E-3, 'slit':'R1C2', 'slit_dec_offset_mas':base_scene.point_source_ddec[0]}
optics_slit_prism_cfam3F = instrument.CorgiOptics(cgi_mode, bandpass='3F', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_slit_prism_cfam3D = instrument.CorgiOptics(cgi_mode, bandpass='3D', optics_keywords=offset_star_optics_keywords, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
Get the occulted star PSF with the slit in place for each filter case 3F and 3D
[14]:
sim_unocc_slit_prism_cfam3F = optics_slit_prism_cfam3F.get_host_star_psf(base_scene)
sim_unocc_slit_prism_cfam3D = optics_slit_prism_cfam3D.get_host_star_psf(base_scene)
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.000, 60.001
full frame source location (x, y) with prism = 1600.000, 525.001
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.044, 51.460
full frame source location (x, y) with prism = 1600.044, 516.460
[15]:
image_unocc_slit_prism_cfam3F = sim_unocc_slit_prism_cfam3F.host_star_image.data
image_unocc_slit_prism_cfam3D = sim_unocc_slit_prism_cfam3D.host_star_image.data
[16]:
print(np.sum(image_unocc_slit_prism_cfam3F) / np.sum(image_unocc_noslit_prism_cfam3F))
print(np.sum(image_unocc_slit_prism_cfam3D) / np.sum(image_unocc_noslit_prism_cfam3D))
0.5313299168383959
0.503380779955182
Plot the results to compare prism images with and without the slit in place.
[17]:
fig = plt.figure(figsize=(20,8))
plt.subplots_adjust(wspace=0.10)
xcrop = 40
plt.subplot(141)
plt.imshow(image_unocc_noslit_prism_cfam3F[xcrop:,xcrop:-xcrop],origin='lower')
plt.title(f'CFAM 3F, FSAM OPEN, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(142)
plt.imshow(image_unocc_slit_prism_cfam3F[xcrop:,xcrop:-xcrop],origin='lower')
plt.title(f'CFAM 3F, FSAM R1C2, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(143)
plt.imshow(image_unocc_noslit_prism_cfam3D[xcrop:,xcrop:-xcrop],origin='lower')
plt.title(f'CFAM 3D, FSAM OPEN, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(144)
plt.imshow(image_unocc_slit_prism_cfam3D[xcrop:,xcrop:-xcrop],origin='lower')
plt.title(f'CFAM 3D, FSAM R1C2, PRISM3')
plt.colorbar(shrink=0.5)
[17]:
<matplotlib.colorbar.Colorbar at 0x78d8458d30e0>
Set the optics configuration for the target scene, repeated with and without the slit in place.
[18]:
## Define the polaxis parameter. Use 10 for non-polaxis cases only, as other options are not yet implemented.
polaxis = 10
# output_dim define the size of the output image
output_dim = 121
overfac = 3 # Increase this to 5 for higher accuracy
band = '3F'
#set slit and prism keywords to none
optics_keywords_noslit_noprism ={'cor_type':cor_type, 'use_errors':1, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':1, 'dm1_v':dm1, 'use_dm2':1, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1, 'slit':'None',
'prism':'None'}
optics_keywords_slit_noprism ={'cor_type':cor_type, 'use_errors':1, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':1, 'dm1_v':dm1, 'use_dm2':1, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1, 'slit':'R1C2',
'slit_x_offset_mas':base_scene.point_source_dra[0], 'slit_y_offset_mas':base_scene.point_source_ddec[0],
'prism':'None'}
optics_keywords_slit_prism ={'cor_type':cor_type, 'use_errors':1, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':1, 'dm1_v':dm1, 'use_dm2':1, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1, 'slit':'R1C2',
'slit_x_offset_mas':base_scene.point_source_dra[0], 'slit_y_offset_mas':base_scene.point_source_ddec[0],
'prism':'PRISM3', 'wav_step_um':2E-3}
optics_noslit_noprism = instrument.CorgiOptics(cgi_mode, bandpass=band, optics_keywords=optics_keywords_noslit_noprism, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_slit_noprism = instrument.CorgiOptics(cgi_mode, bandpass=band, optics_keywords=optics_keywords_slit_noprism, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
optics_slit_prism = instrument.CorgiOptics(cgi_mode, bandpass=band, optics_keywords=optics_keywords_slit_prism, if_quiet=True,
oversampling_factor = overfac, return_oversample = False)
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:218: UserWarning: No prism selected in spec mode, the dispersion model will not be applied to the image cube.
warnings.warn("No prism selected in spec mode, the dispersion model will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:202: UserWarning: Slit location provided in EXCAM coordinates (x, y). These values will override the sky-coordinate inputs (dRA, dDec). Please ensure the EXCAM coordinates correspond to the intended slit position on the sky.
warnings.warn(
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:218: UserWarning: No prism selected in spec mode, the dispersion model will not be applied to the image cube.
warnings.warn("No prism selected in spec mode, the dispersion model will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:202: UserWarning: Slit location provided in EXCAM coordinates (x, y). These values will override the sky-coordinate inputs (dRA, dDec). Please ensure the EXCAM coordinates correspond to the intended slit position on the sky.
warnings.warn(
3. On-axis star with companion source
Images without companion
[19]:
sim_scene_noslit_noprism = optics_noslit_noprism.get_host_star_psf(base_scene)
[20]:
sim_scene_slit_noprism = optics_slit_noprism.get_host_star_psf(base_scene)
[21]:
sim_scene_slit_prism = optics_slit_prism.get_host_star_psf(base_scene)
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.000, 60.001
full frame source location (x, y) with prism = 1600.000, 525.001
[22]:
image_star_noslit_noprism = sim_scene_noslit_noprism.host_star_image.data
image_star_slit_noprism = sim_scene_slit_noprism.host_star_image.data
image_star_slit_prism = sim_scene_slit_prism.host_star_image.data
Images with companion
[23]:
optics_slit_prism.inject_point_sources(base_scene, sim_scene_slit_prism)
[23]:
<corgisim.scene.SimulatedImage at 0x78d84572f830>
[24]:
optics_noslit_noprism.inject_point_sources(base_scene, sim_scene_noslit_noprism)
[24]:
<corgisim.scene.SimulatedImage at 0x78d844700050>
[25]:
image_comp_noslit_noprism = sim_scene_noslit_noprism.point_source_image.data
combined_image_noslit_noprism = image_star_noslit_noprism + image_comp_noslit_noprism
image_comp_slit_prism = sim_scene_slit_prism.point_source_image.data
combined_image_slit_prism = image_star_slit_prism + image_comp_slit_prism
[26]:
fig = plt.figure(figsize=(16,8))
plt.subplots_adjust(wspace=0.12)
xcrop = 30
plt.subplot(131)
plt.imshow(image_star_noslit_noprism[:,xcrop:-xcrop], origin='lower')
plt.title(f'SPC on Vmag={Vmag} star, {dm_case} DM case,\nFSAM OPEN, no prism')
plt.colorbar(shrink=0.5)
plt.subplot(132)
plt.imshow(image_star_slit_noprism[:,xcrop:-xcrop], origin='lower')
plt.title(f'SPC on Vmag={Vmag} star, {dm_case} DM case,\nFSAM R1C2, no prism')
plt.colorbar(shrink=0.5)
plt.subplot(133)
plt.imshow(image_star_slit_prism[:,xcrop:-xcrop], origin='lower')
plt.title(f'SPC on Vmag={Vmag} star, {dm_case} DM case,\nFSAM R1C2, PRISM3')
plt.colorbar(shrink=0.5)
[26]:
<matplotlib.colorbar.Colorbar at 0x78d845621940>
[27]:
fig = plt.figure(figsize=(16,8))
plt.subplots_adjust(wspace=0.12)
xcrop = 30
plt.subplot(131)
plt.imshow(image_star_noslit_noprism[:,xcrop:-xcrop], origin='lower')
plt.title(f'SPC on Vmag={Vmag} star, {dm_case} DM case,\nFSAM OPEN, no prism')
plt.colorbar(shrink=0.5)
plt.subplot(132)
plt.imshow(image_comp_noslit_noprism[:,xcrop:-xcrop], origin='lower')
plt.title(f'Planet at flux ratio {scene_mean_fluxratio:.1E},\nFSAM OPEN, no prism')
plt.colorbar(shrink=0.5)
plt.subplot(133)
plt.imshow(combined_image_noslit_noprism[:,xcrop:-xcrop], origin='lower')
plt.title('Combined image')
plt.colorbar(shrink=0.5)
[27]:
<matplotlib.colorbar.Colorbar at 0x78d844e0ba70>
[28]:
fig = plt.figure(figsize=(16,6))
plt.subplots_adjust(wspace=0.15)
xcrop = 30
plt.subplot(131)
plt.imshow(image_star_slit_prism[xcrop:,xcrop:-xcrop],origin='lower')
plt.title(f'Vmag={Vmag} star, {dm_case} DM case,\nFSAM R1C2, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(132)
plt.imshow(image_comp_slit_prism[xcrop:,xcrop:-xcrop],origin='lower')
plt.title(f'Planet at flux ratio {scene_mean_fluxratio:.1E},\nFSAM R1C2, PRISM3')
plt.colorbar(shrink=0.5)
plt.subplot(133)
plt.imshow(combined_image_slit_prism[xcrop:,xcrop:-xcrop],origin='lower')
plt.title('Combined image')
plt.colorbar(shrink=0.5)
[28]:
<matplotlib.colorbar.Colorbar at 0x78d845262810>
4. Detector Image
Add detector noise
[29]:
#simulate detector noise
gain = 400
emccd_keywords ={'em_gain':gain, 'cr_rate':0}
detector = instrument.CorgiDetector(emccd_keywords)
exptime = (8 * u.hour).to_value(u.s)
#use configuration with slit and prism as example
sim_scene_slit_prism = detector.generate_detector_image(sim_scene_slit_prism,exptime)
image_tot_sub= sim_scene_slit_prism.image_on_detector.data
[30]:
#plot image with detector noise
plt.imshow(image_tot_sub,origin='lower')
plt.title('Spec image with detector noise')
co = plt.colorbar(shrink=0.7)
Full frame L1 image
[31]:
#simulate full frame detector image
sim_scene_slit_prism = detector.generate_detector_image(sim_scene_slit_prism,exptime,full_frame=True,loc_x=512, loc_y=512)
image_tot_full = sim_scene_slit_prism.image_on_detector[1].data
[32]:
#plot full frame detector image
plt.imshow(image_tot_full,origin='lower')
plt.title('Full frame spec image')
co = plt.colorbar(shrink=0.7)
5. Rotated SPC and slit
[33]:
# Define the planet position relative to the host star, in milliarcseconds (mas)
# For reference: 1 λ/D at 550 nm with a 2.3 m telescope is ~49.3 mas
mas_per_lamD = 63.72 # Band 3
dx = 6 * mas_per_lamD # X position in mas
dy = 3 * mas_per_lamD # Y position in mas
# Construct a list of dictionaries for all companion point sources
point_source_info = [
{
'Vmag': Vmag_planet_scene,
'magtype': 'vegamag',
'position_x': dx,
'position_y': dy,
'Custom_Spectrum': sp_planet, # Planet spectrum model
'Rescale_Custom_Spectrum': True # Rescale the planet spectrum to match Vmag
}
]
# --- Create the Astrophysical Scene ---
# This Scene object combines the host star and companion(s)
base_scene = scene.Scene(host_star_properties, point_source_info)
# --- Access the generated stellar spectrum ---
sp_star = base_scene.stellar_spectrum
# --- Access the generated companion spectrum ---
sp_comp = base_scene.off_axis_source_spectrum
Adding 1 off-axis sources
[34]:
import os
os.listdir(roman_preflight_proper.lib_dir + '/examples/')
[34]:
['hlc_ni_3e-8_dm2_v.fits',
'__init__.py',
'spc-wide_ni_3e-9_dm1_v.fits',
'spc-wide_flat_wfe_dm2_v.fits',
'spc-wide_ni_2e-8_dm1_v.fits',
'hlc_ni_2e-9_dm2_v.fits',
'run_defocus.py',
'run_spc_wide.py',
'spc-spec_ni_4e-9_dm1_v.fits',
'spc-spec_ni_1e-9_dm1_v.fits',
'hlc_flat_wfe_dm2_v.fits',
'spc-spec_ni_2e-8_dm1_v.fits',
'spc-wide_ni_5e-9_dm2_v.fits',
'spc-spec_flat_wfe_dm2_v.fits',
'hlc_ni_5e-9_dm2_v.fits',
'__pycache__',
'hlc_ni_5e-9_dm1_v.fits',
'spc-spec_flat_wfe_dm1_v.fits',
'spc-wide_ni_5e-9_dm1_v.fits',
'run_hlc.py',
'run_spc_spec.py',
'spc-spec_ni_2e-8_dm2_v.fits',
'run_flatten.py',
'hlc_flat_wfe_dm1_v.fits',
'spc-spec_ni_1e-9_dm2_v.fits',
'spc-spec_ni_4e-9_dm2_v.fits',
'hlc_ni_2e-9_dm1_v.fits',
'spc-wide_ni_2e-8_dm2_v.fits',
'spc-wide_flat_wfe_dm1_v.fits',
'spc-wide_ni_3e-9_dm2_v.fits',
'hlc_ni_3e-8_dm1_v.fits']
[35]:
cgi_mode = 'spec'
cor_type = 'spc-spec_band3_rotated'
prism_name = 'PRISM2'
slit_name = 'R2C2'
band = '3F'
rootname = 'spc-spec_ni_' + dm_case
dm1 = proper.prop_fits_read( roman_preflight_proper.lib_dir + '/examples/'+rootname+'_dm1_v.fits' )
dm2 = proper.prop_fits_read( roman_preflight_proper.lib_dir + '/examples/'+rootname+'_dm2_v.fits' )
## Define the polaxis parameter. Use 10 for non-polaxis cases only, as other options are not yet implemented.
polaxis = 10
# output_dim define the size of the output image
output_dim = 121
overfac = 5
#set slit and prism keywords to none
optics_keywords_noslit_noprism ={'cor_type':cor_type, 'use_errors':0, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':0, 'dm1_v':dm1, 'use_dm2':0, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1,
'slit':'None', 'prism':'None'}
optics_keywords_slit_noprism ={'cor_type':cor_type, 'use_errors':0, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':0, 'dm1_v':dm1, 'use_dm2':0, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1,
'slit':slit_name, 'prism':'None',
'slit_x_offset_mas':base_scene.point_source_dra[0], 'slit_y_offset_mas':base_scene.point_source_ddec[0]}
optics_keywords_slit_prism ={'cor_type':cor_type, 'use_errors':0, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':0, 'dm1_v':dm1, 'use_dm2':0, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1,
'slit':slit_name, 'prism':prism_name, 'wav_step_um':2E-3,
'slit_x_offset_mas':base_scene.point_source_dra[0], 'slit_y_offset_mas':base_scene.point_source_ddec[0]}
optics_noslit_noprism = instrument.CorgiOptics(cgi_mode, bandpass=band, optics_keywords=optics_keywords_noslit_noprism, if_quiet=True,
oversample = overfac, return_oversample = False, roll_angle=0.0)
optics_slit_noprism = instrument.CorgiOptics(cgi_mode, bandpass=band, optics_keywords=optics_keywords_slit_noprism, if_quiet=True,
oversample = overfac, return_oversample = False, roll_angle=0.0)
optics_slit_prism = instrument.CorgiOptics(cgi_mode, bandpass=band, optics_keywords=optics_keywords_slit_prism, if_quiet=True,
oversample = overfac, return_oversample = False, roll_angle=0.0)
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
CorgiOptics initialized with proper keywords.
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:218: UserWarning: No prism selected in spec mode, the dispersion model will not be applied to the image cube.
warnings.warn("No prism selected in spec mode, the dispersion model will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:202: UserWarning: Slit location provided in EXCAM coordinates (x, y). These values will override the sky-coordinate inputs (dRA, dDec). Please ensure the EXCAM coordinates correspond to the intended slit position on the sky.
warnings.warn(
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:218: UserWarning: No prism selected in spec mode, the dispersion model will not be applied to the image cube.
warnings.warn("No prism selected in spec mode, the dispersion model will not be applied to the image cube.")
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:202: UserWarning: Slit location provided in EXCAM coordinates (x, y). These values will override the sky-coordinate inputs (dRA, dDec). Please ensure the EXCAM coordinates correspond to the intended slit position on the sky.
warnings.warn(
[36]:
sim_scene_noslit_noprism = optics_noslit_noprism.get_host_star_psf(base_scene)
[37]:
sim_scene_slit_noprism = optics_slit_noprism.get_host_star_psf(base_scene)
[38]:
sim_scene_slit_prism = optics_slit_prism.get_host_star_psf(base_scene)
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.020, 37.896
full frame source location (x, y) with prism = 1600.020, 502.896
Temporarily, these images are flipped left-right to compensate for the incorrect orientation of the rotated SPC bowtie mask
Compute images with companion
[39]:
optics_slit_prism.inject_point_sources(base_scene, sim_scene_slit_prism)
[39]:
<corgisim.scene.SimulatedImage at 0x78d845333f80>
[40]:
optics_noslit_noprism.inject_point_sources(base_scene, sim_scene_noslit_noprism)
[40]:
<corgisim.scene.SimulatedImage at 0x78d844e69f10>
[41]:
image_star_noslit_noprism = sim_scene_noslit_noprism.host_star_image.data
image_star_slit_noprism = sim_scene_slit_noprism.host_star_image.data
image_star_slit_prism = sim_scene_slit_prism.host_star_image.data
[42]:
image_comp_noslit_noprism = sim_scene_noslit_noprism.point_source_image.data
combined_image_noslit_noprism = image_star_noslit_noprism + image_comp_noslit_noprism
image_comp_slit_prism = sim_scene_slit_prism.point_source_image.data
combined_image_slit_prism = image_star_slit_prism + image_comp_slit_prism
[43]:
fig = plt.figure(figsize=(16,8))
plt.subplots_adjust(wspace=0.12)
xcrop = 20
ycrop = 15
plt.subplot(131)
plt.imshow(image_star_noslit_noprism[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
# plt.title(f'SPC on Vmag={Vmag} star, {cases[0]} DM case,\nFSAM OPEN, no prism')
plt.title(f'Rotated Band 3 SPC on Vmag={Vmag} star,\nFSAM OPEN, no prism, errors off, DMs off')
plt.colorbar(shrink=0.5)
plt.subplot(132)
plt.imshow(image_star_slit_noprism[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
plt.title(f'Rotated Band 3 SPC on Vmag={Vmag} star,\nFSAM {slit_name}, no prism, errors off, DMs off')
plt.colorbar(shrink=0.5)
plt.subplot(133)
plt.imshow(image_star_slit_prism[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
plt.title(f'Rotated Band 3 SPC on Vmag={Vmag} star,\nFSAM {slit_name}, {prism_name}, errors off, DMs off')
plt.colorbar(shrink=0.5)
[43]:
<matplotlib.colorbar.Colorbar at 0x78d844d58230>
[44]:
fig = plt.figure(figsize=(16,8))
plt.subplots_adjust(wspace=0.12)
xcrop = 20
ycrop = 15
plt.subplot(131)
plt.imshow(image_star_noslit_noprism[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
# plt.title(f'SPC on Vmag={Vmag} star, {cases[0]} DM case,\nFSAM OPEN, no prism')
plt.title(f'Rotated Band 3 SPC on Vmag={Vmag} star,\nFSAM {slit_name}, {prism_name}, errors off, DMs off')
plt.colorbar(shrink=0.5)
plt.subplot(132)
plt.imshow(image_comp_noslit_noprism[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
plt.title(f'Companion Vmag={Vmag_planet_scene},\nFSAM OPEN, no prism')
plt.colorbar(shrink=0.5)
plt.subplot(133)
plt.imshow(combined_image_noslit_noprism[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
plt.title('Combined image')
plt.colorbar(shrink=0.5)
[44]:
<matplotlib.colorbar.Colorbar at 0x78d844c2bd10>
[45]:
fig = plt.figure(figsize=(16,6))
plt.subplots_adjust(wspace=0.15)
xcrop = 20
ycrop = 15
plt.subplot(131)
plt.imshow(image_star_slit_prism[ycrop:-ycrop,xcrop:-xcrop],origin='lower')
plt.title(f'Rotated Band 3 SPC on Vmag={Vmag} star,\nFSAM {slit_name}, {prism_name}, errors off, DMs off')
plt.colorbar(shrink=0.5)
plt.subplot(132)
plt.imshow(image_comp_slit_prism[ycrop:-ycrop,xcrop:-xcrop],origin='lower')
plt.title(f'Vmag={Vmag_planet_scene} companion,\nFSAM {slit_name}, {prism_name}')
plt.colorbar(shrink=0.5)
plt.subplot(133)
plt.imshow(combined_image_slit_prism[ycrop:-ycrop,xcrop:-xcrop],origin='lower')
plt.title('Combined image')
plt.colorbar(shrink=0.5)
[45]:
<matplotlib.colorbar.Colorbar at 0x78d8451bc3e0>
Add detector noise
[46]:
#simulate detector noise
gain = 400
emccd_keywords ={'em_gain':gain, 'cr_rate':0}
detector = instrument.CorgiDetector(emccd_keywords)
exptime = (8 * u.hour).to_value(u.s)
#use configuration with slit and prism as example
sim_scene_slit_prism = detector.generate_detector_image(sim_scene_slit_prism,exptime)
detector_image = sim_scene_slit_prism.image_on_detector.data
[47]:
xcrop = 20
ycrop = 15
plt.imshow(detector_image[ycrop:-ycrop,xcrop:-xcrop], origin='lower')
plt.title('Spec image with detector noise')
co = plt.colorbar(shrink=0.7)
Full frame L1 image
[48]:
#simulate full frame detector image
sim_scene_slit_prism = detector.generate_detector_image(sim_scene_slit_prism, exptime, full_frame=True, loc_x=512, loc_y=512)
image_tot_full = sim_scene_slit_prism.image_on_detector[1].data
[49]:
#plot full frame detector image
plt.imshow(image_tot_full,origin='lower')
plt.title('Full frame spec image')
co = plt.colorbar(shrink=0.7)
[50]:
outputs.save_hdu_to_fits(sim_scene_slit_prism.image_on_detector, outdir='.', write_as_L1=True)
L1_fitsname = sim_scene_slit_prism.image_on_detector[0].header['FILENAME']
Saved FITS file to: ./cgi_0200001001001001001_20260709t1459080_l1_.fits
Add Satellite Spots
[51]:
Vmag = 0.46 # V-band magnitude of the host star
sptype = 'B6V' # Spectral type of the host star
ref_flag = False # if the target is a reference star or not, default is False
host_star_properties = {'Vmag': Vmag,
'spectral_type': sptype,
'magtype': 'vegamag',
'ref_flag': False}
# --- Build stellar spectrum via a star-only scene ---
base_scene = scene.Scene(host_star_properties)
cgi_mode = 'spec'
cor_type = 'spc-spec_band3'
dm_case = '1e-9'
dm1 = proper.prop_fits_read( roman_preflight_proper.lib_dir + '/examples/spc-spec_ni_' + dm_case + '_dm1_v.fits' )
dm2 = proper.prop_fits_read( roman_preflight_proper.lib_dir + '/examples/spc-spec_ni_' + dm_case + '_dm2_v.fits' )
polaxis = 10
# output_dim define the size of the output image
output_dim = 121
optics_keywords_noslit_prism ={'cor_type':cor_type, 'use_errors':1, 'polaxis':polaxis, 'output_dim':output_dim,
'use_dm1':1, 'dm1_v':dm1, 'use_dm2':1, 'dm2_v':dm2,'use_fpm':1, 'use_lyot_stop':1, 'slit':'None',
'prism':'PRISM3', 'wav_step_um':2E-3}
optics_noslit_prism = instrument.CorgiOptics(cgi_mode, bandpass='3D', optics_keywords=optics_keywords_noslit_prism, if_quiet=True, return_oversample = False)
sim_scene_noslit_prism = optics_noslit_prism.get_host_star_psf(base_scene)
satspot_keywords = {'num_pairs':2, 'sep_lamD': 6.25, 'angle_deg': [0,90], 'contrast': 1e-7}
optics_noslit_prism.add_satspot(satspot_keywords=satspot_keywords)
sim_scene_noslit_prism_with_satspots = optics_noslit_prism.get_host_star_psf(base_scene)
fig = plt.figure(figsize=(12,3))
plt.subplot(131)
plt.imshow(sim_scene_noslit_prism.host_star_image.data)
plt.colorbar()
plt.title('Host Star Image')
plt.subplot(132)
plt.imshow(sim_scene_noslit_prism_with_satspots.host_star_image.data)
plt.colorbar()
plt.title('Host Star Image with satellite spots')
plt.subplot(133)
plt.imshow(sim_scene_noslit_prism_with_satspots.host_star_image.data - sim_scene_noslit_prism.host_star_image.data)
plt.colorbar()
plt.title('Satellite spots')
fig.suptitle('Spectroscopy mode prism no slit')
fig.subplots_adjust(top=0.8)
Warning: BPGS atlas file /home/snoiret/Documents/Corgisim/.envCorgisim/lib/python3.12/site-packages/eetc/flux_grid_generation/bpgs_atlas_csv/ not found.
Falling back to blackbody with T=14633.333333333308K
CorgiOptics initialized with proper keywords.
/home/snoiret/Documents/Corgisim/corgisim/corgisim/instrument.py:233: UserWarning: No slit selected in spec mode, the slit mask will not be applied to the image cube.
warnings.warn("No slit selected in spec mode, the slit mask will not be applied to the image cube.")
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.044, 51.460
full frame source location (x, y) with prism = 1600.044, 516.460
source location (x, y) without prism = 60.000, 60.000
source location (x, y) with prism = 60.044, 51.460
full frame source location (x, y) with prism = 1600.044, 516.460