Commit 1aef56b6 authored by GZhao's avatar GZhao
Browse files

different dm volt can be choose for each exposure

parent 5c15aae8
Pipeline #8681 passed with stage
in 0 seconds
...@@ -8,3 +8,8 @@ CpicImgSim is a Python library for numerical simulation of the observational ima ...@@ -8,3 +8,8 @@ CpicImgSim is a Python library for numerical simulation of the observational ima
数据文件:https://pan.cstcloud.cn/s/gjMlzXRuRsM 提取密码:i3Zs 数据文件:https://pan.cstcloud.cn/s/gjMlzXRuRsM 提取密码:i3Zs
程序文档:https://csst-tb.bao.ac.cn/simulation/cpic/index.html 程序文档:https://csst-tb.bao.ac.cn/simulation/cpic/index.html
联系方式:南京天光所 赵刚 gzhao@niaot.ac.cn 025-85482316 联系方式:南京天光所 赵刚 gzhao@niaot.ac.cn 025-85482316
## 软件更新日志
2025年6月5日:添加了新的宇宙线生成模块,使用主巡天内的模块代码。新的模块可以更好的兼容通用的宇宙线识别模块。设置方法:在run_config 里添加msc_cr_model: true条目可以启用新的宇宙线生成模块。
2025年6月10日:增加了波前电压设置功能。现在对于每一次曝光可以设置不同的波前电压。在观测yaml中增加dm_volt_index: xxx选项。xxx为整形,例如565, 661等。另外支持1, 2, 3, 4选项,为四个不同方向的暗区。实验功能:dm_volt_index可设置-1,自动选择和波段匹配的暗区(该功能谨慎使用)。
...@@ -4,13 +4,13 @@ import numpy as np ...@@ -4,13 +4,13 @@ import numpy as np
import scipy.ndimage as nd import scipy.ndimage as nd
from astropy.io import fits from astropy.io import fits
from .config import config, S from .config import config, S, cpism_refdata
from .utils import region_replace, random_seed_select from .utils import region_replace, random_seed_select
from .io import log from .io import log
from .optics import filter_throughput from .optics import filter_throughput
from .msc_cr import produceCR_Map from .msc_cr import produceCR_Map
cpism_refdata = config['cpism_refdata'] # cpism_refdata = config['cpism_refdata']
MAG_SYSTEM = config['mag_system'] MAG_SYSTEM = config['mag_system']
solar_spectrum = S.FileSpectrum(config['solar_spectrum']) solar_spectrum = S.FileSpectrum(config['solar_spectrum'])
solar_spectrum.convert('photlam') solar_spectrum.convert('photlam')
...@@ -260,7 +260,7 @@ class CosmicRayFrameMaker(object): ...@@ -260,7 +260,7 @@ class CosmicRayFrameMaker(object):
exTime=expt, exTime=expt,
cr_pixelRatio=0.003*expt/600., # 5e-6/pixel , 1.3e-6 for cpic package cr_pixelRatio=0.003*expt/600., # 5e-6/pixel , 1.3e-6 for cpic package
gain=1, # gain = 1, means the unit of output image is electron gain=1, # gain = 1, means the unit of output image is electron
attachedSizes=self.attachedSizes) attachedSizes=self.attachedSize)
return cr_map return cr_map
for i in range(len(cr_array)): for i in range(len(cr_array)):
...@@ -881,8 +881,6 @@ class CpicVisEmccd(object): ...@@ -881,8 +881,6 @@ class CpicVisEmccd(object):
em_fix = self.em_fix_fuc_fit(emgain) * emgain em_fix = self.em_fix_fuc_fit(emgain) * emgain
image = np.random.gamma(image, em_fix) + image * (emgain - em_fix) image = np.random.gamma(image, em_fix) + image * (emgain - em_fix)
fits.writeto("image.fits", image, overwrite=True)
if self.switch['em_blooming']: if self.switch['em_blooming']:
image = self.emregester_blooming(image) image = self.emregester_blooming(image)
......
...@@ -53,19 +53,22 @@ def load_refdata_path(config_aim): ...@@ -53,19 +53,22 @@ def load_refdata_path(config_aim):
refdata_list.append(refdata) refdata_list.append(refdata)
with open(config_aim, 'w') as f: with open(config_aim, 'w') as f:
yaml.dump(refdata_list, f) yaml.dump(refdata_list, f)
print(f"refdata path successfully set to be {refdata}")
else:
print(f"{refdata} is not a valid path")
exit() exit()
cpism_refdata = load_refdata_path(config_aim) cpism_refdata = load_refdata_path(config_aim)
config = {} config = {}
config['cpism_refdata'] = cpism_refdata # config['cpism_refdata'] = cpism_refdata
config['utc0'] = '2024-05-01T00:00:00' config['utc0'] = '2024-05-01T00:00:00'
config['hybrid_model'] = f'{cpism_refdata}/target_model/hybrid_model.fits' config['hybrid_model'] = f'{cpism_refdata}/target_model/hybrid_model.fits'
config['bcc_model'] = f'{cpism_refdata}/target_model/bccmodels' config['bcc_model'] = f'{cpism_refdata}/target_model/bccmodels'
config['mag_system'] = 'abmag' config['mag_system'] = 'abmag'
config['apm_file'] = f'{cpism_refdata}/optics/apm.fits' config['apm_file'] = f'{cpism_refdata}/optics/apm.fits'
config['actuator_file'] = f'{cpism_refdata}/optics/actuator.fits'
config['aberration'] = f'{cpism_refdata}/optics/initial_phase_aberration.fits' config['aberration'] = f'{cpism_refdata}/optics/initial_phase_aberration.fits'
config['mask_width'] = 0.4 config['mask_width'] = 0.4
config['check_fits_header'] = False config['check_fits_header'] = False
...@@ -93,10 +96,25 @@ config['catalog_folder'] = f'{cpism_refdata}/demo_catalog' ...@@ -93,10 +96,25 @@ config['catalog_folder'] = f'{cpism_refdata}/demo_catalog'
config['csst_format'] = True config['csst_format'] = True
config['nsample'] = 1 config['nsample'] = 1
config['msc_cr_model'] = False config['msc_cr_model'] = False
config['dm_volt_group'] = {
1: f'{cpism_refdata}/optics/dark_zone_0011_volt.fits',
2: f'{cpism_refdata}/optics/dark_zone_0110_volt.fits',
3: f'{cpism_refdata}/optics/dark_zone_1100_volt.fits',
4: f'{cpism_refdata}/optics/dark_zone_1001_volt.fits',
565: f'{cpism_refdata}/optics/dark_zone_1100_F565_volt.fits',
661: f'{cpism_refdata}/optics/dark_zone_1100_F661_volt.fits',
743: f'{cpism_refdata}/optics/dark_zone_1100_F743_volt.fits',
883: f'{cpism_refdata}/optics/dark_zone_1100_F883_volt.fits',
520: f'{cpism_refdata}/optics/dark_zone_1100_F520_volt.fits',
662: f'{cpism_refdata}/optics/dark_zone_1100_F662_volt.fits',
850: f'{cpism_refdata}/optics/dark_zone_1100_F850_volt.fits',
720: f'{cpism_refdata}/optics/dark_zone_1100_F720_volt.fits',
}
config['wavefront_error'] = 0.075 # nm
update_able_keys = [ update_able_keys = [
'apm_file', 'actuator_file', 'aberration', 'apm_file', 'aberration', 'wavefront_error',
'log_dir', 'log_level', 'catalog_folder', 'msc_cr_model' 'log_dir', 'log_level', 'catalog_folder', 'msc_cr_model',
'nsample', 'csst_format', 'output', 'check_fits_header' 'nsample', 'csst_format', 'output', 'check_fits_header'
] ]
......
...@@ -10,7 +10,6 @@ from datetime import datetime ...@@ -10,7 +10,6 @@ from datetime import datetime
import traceback import traceback
import numpy as np import numpy as np
from astropy.io import fits
from .target import spectrum_generator, target_file_load from .target import spectrum_generator, target_file_load
from .optics import focal_mask, focal_convolve from .optics import focal_mask, focal_convolve
...@@ -18,7 +17,7 @@ from .camera import CosmicRayFrameMaker, sky_frame_maker, CpicVisEmccd ...@@ -18,7 +17,7 @@ from .camera import CosmicRayFrameMaker, sky_frame_maker, CpicVisEmccd
from .io import save_fits, log from .io import save_fits, log
from .config import update_able_keys, relative_time from .config import update_able_keys, relative_time
from .config import config as default_config, replace_cpism_refdata from .config import config as default_config, replace_cpism_refdata
from .psf_simulation import actuator # from .psf_simulation import actuators
def vis_observation( def vis_observation(
...@@ -39,7 +38,8 @@ def vis_observation( ...@@ -39,7 +38,8 @@ def vis_observation(
emgain=None, emgain=None,
prograss_bar=None, prograss_bar=None,
output='./', output='./',
dataset='default' dataset='default',
dm_volt_index=1,
) -> np.ndarray: ) -> np.ndarray:
"""Observation simulation main process on visable band using EMCCD. """Observation simulation main process on visable band using EMCCD.
...@@ -87,6 +87,7 @@ def vis_observation( ...@@ -87,6 +87,7 @@ def vis_observation(
platescale = default_config['platescale'] platescale = default_config['platescale']
iwa = default_config['mask_width'] / 2 iwa = default_config['mask_width'] / 2
area = default_config['aperature_area'] area = default_config['aperature_area']
error = default_config['wavefront_error']
expt_start = camera.system_time expt_start = camera.system_time
target_list = [] target_list = []
...@@ -133,7 +134,9 @@ def vis_observation( ...@@ -133,7 +134,9 @@ def vis_observation(
init_shifts=shift, init_shifts=shift,
rotation=rotation, rotation=rotation,
nsample=nsample, nsample=nsample,
platesize=camera.flat_shape error=error,
platesize=camera.flat_shape,
dm_volt_index=dm_volt_index
) )
if skybg is None or skybg > 100: if skybg is None or skybg > 100:
...@@ -330,9 +333,9 @@ def observation_simulation_from_config(obs_file, config_file): ...@@ -330,9 +333,9 @@ def observation_simulation_from_config(obs_file, config_file):
deduplicate_names_add_count(all_camera_name) deduplicate_names_add_count(all_camera_name)
if 'actuator_file' in config.keys(): # if 'actuator_file' in config.keys():
actuator_data = fits.getdata(config['actuator_file']) # actuator_data = fits.getdata(config['actuator_file'])
actuator[:] = actuator_data[:] # actuator[:] = actuator_data[:]
for key in config.keys(): for key in config.keys():
if key in update_able_keys: if key in update_able_keys:
...@@ -377,6 +380,7 @@ def observation_simulation_from_config(obs_file, config_file): ...@@ -377,6 +380,7 @@ def observation_simulation_from_config(obs_file, config_file):
emgain = obs_info.get('emgain', None) emgain = obs_info.get('emgain', None)
time = relative_time(time) time = relative_time(time)
dataset = obs_info.get('dataset', 'default') dataset = obs_info.get('dataset', 'default')
dm_volt_index = obs_info.get('dm_volt_index', 1)
except Exception as e: except Exception as e:
log.error(f"{file} is not a valid yaml file.") log.error(f"{file} is not a valid yaml file.")
...@@ -424,7 +428,9 @@ def observation_simulation_from_config(obs_file, config_file): ...@@ -424,7 +428,9 @@ def observation_simulation_from_config(obs_file, config_file):
csst_format=csst_format, csst_format=csst_format,
crmaker=crmaker, crmaker=crmaker,
dataset=dataset, dataset=dataset,
prograss_bar=True) prograss_bar=True,
dm_volt_index=dm_volt_index,
)
except Exception as e: except Exception as e:
log.error(f"{info_text} failed with {type(e).__name__}{e}.\n\n {traceback.format_exc()}") log.error(f"{info_text} failed with {type(e).__name__}{e}.\n\n {traceback.format_exc()}")
......
...@@ -133,7 +133,8 @@ def focal_convolve( ...@@ -133,7 +133,8 @@ def focal_convolve(
rotation: float = 0, rotation: float = 0,
nsample: int = 5, nsample: int = 5,
error: float = 0, error: float = 0,
platesize: list = [1024, 1024]) -> np.ndarray: platesize: list = [1024, 1024],
dm_volt_index: int = 1) -> np.ndarray:
"""PSF convolution of the ideal focus image. """PSF convolution of the ideal focus image.
Parameters Parameters
...@@ -184,6 +185,9 @@ def focal_convolve( ...@@ -184,6 +185,9 @@ def focal_convolve(
if not targets: if not targets:
return np.zeros((platesize[1], platesize[0])) return np.zeros((platesize[1], platesize[0]))
if dm_volt_index == -1: # experimental function, be careful to use it.
dm_volt_index = int(band[1:])
for i_wave in range(nsample): for i_wave in range(nsample):
d_wave = (max_wave - min_wave) / nsample d_wave = (max_wave - min_wave) / nsample
wave0 = min_wave + i_wave * d_wave wave0 = min_wave + i_wave * d_wave
...@@ -195,11 +199,15 @@ def focal_convolve( ...@@ -195,11 +199,15 @@ def focal_convolve(
i_band = S.ArrayBandpass(wave, i_throughput, waveunits='angstrom') i_band = S.ArrayBandpass(wave, i_throughput, waveunits='angstrom')
i_fp_image = ideal_focus_image(i_band, targets[1:], platescale, platesize, init_shifts, rotation) i_fp_image = ideal_focus_image(i_band, targets[1:], platescale, platesize, init_shifts, rotation)
psf = single_band_psf(center_wavelength, error=error) psf = single_band_psf(center_wavelength, error=error, actuator_index=dm_volt_index)
_, _, cstar_sp, _ = targets[0] _, _, cstar_sp, _ = targets[0]
cstar_flux = (cstar_sp * i_band).integrate() cstar_flux = (cstar_sp * i_band).integrate()
cstar_psf = single_band_masked_psf(center_wavelength, error=error, shift=init_shifts) cstar_psf = single_band_masked_psf(
center_wavelength,
error=error,
shift=init_shifts,
actuator_index=dm_volt_index)
c_fp_image = fftconvolve(i_fp_image, psf, mode='same') c_fp_image = fftconvolve(i_fp_image, psf, mode='same')
c_fp_image = focal_mask(c_fp_image, iwa, platescale) c_fp_image = focal_mask(c_fp_image, iwa, platescale)
......
...@@ -17,7 +17,13 @@ ARCSEC2RAD = np.radians(1 / 3600) ...@@ -17,7 +17,13 @@ ARCSEC2RAD = np.radians(1 / 3600)
# initial psf simulation # initial psf simulation
apm, apm_header = fits.getdata(config['apm_file'], header=True) apm, apm_header = fits.getdata(config['apm_file'], header=True)
actuator = fits.getdata(config['actuator_file'])
actuator_files = config['dm_volt_group']
actuators = {}
for key, actuator_file in actuator_files.items():
actuator_data = fits.getdata(actuator_file)
actuators[key] = actuator_data
surface_aberration = fits.getdata(config['aberration']) surface_aberration = fits.getdata(config['aberration'])
pupil_diameter = 2 # m pupil_diameter = 2 # m
...@@ -78,7 +84,8 @@ aberration = SurfaceAberrationAtDistance(aberration, aberration_distance) ...@@ -78,7 +84,8 @@ aberration = SurfaceAberrationAtDistance(aberration, aberration_distance)
def single_band_masked_psf( def single_band_masked_psf(
wavelength: float, wavelength: float,
error: float = 0, error: float = 0,
shift: list = [0, 0]) -> np.ndarray: shift: list = [0, 0],
actuator_index: int = 1) -> np.ndarray:
"""CPIC PSF considering the focal plane mask. """CPIC PSF considering the focal plane mask.
Parameters Parameters
...@@ -89,13 +96,15 @@ def single_band_masked_psf( ...@@ -89,13 +96,15 @@ def single_band_masked_psf(
deformable mirror control error in nm deformable mirror control error in nm
shift : list shift : list
angular shift of the target in arcsec. angular shift of the target in arcsec.
actuator_index : int
actuator index for the observation.
Returns Returns
---------- ----------
psf : np.ndarray psf : np.ndarray
psf in the focal plane. Normalized as the input flux is 1. psf in the focal plane. Normalized as the input flux is 1.
(Note that total flux of the psf is not 1, because it is masked) (Note that total flux of the psf is not 1, because it is masked)
""" """
actuator = actuators[actuator_index]
error = np.random.normal(0, error*1e-9, actuator.shape) error = np.random.normal(0, error*1e-9, actuator.shape)
deformable_mirror.actuators = actuator + error deformable_mirror.actuators = actuator + error
wf = Wavefront(aperture, wavelength) wf = Wavefront(aperture, wavelength)
...@@ -117,7 +126,8 @@ def single_band_masked_psf( ...@@ -117,7 +126,8 @@ def single_band_masked_psf(
def single_band_shift_psf( def single_band_shift_psf(
wavelength: float, wavelength: float,
error: float = 0, error: float = 0,
shift: list = [0, 0]) -> np.ndarray: shift: list = [0, 0],
actuator_index: int = 1) -> np.ndarray:
"""CPIC PSF considering the focal plane mask. """CPIC PSF considering the focal plane mask.
Parameters Parameters
...@@ -135,6 +145,7 @@ def single_band_shift_psf( ...@@ -135,6 +145,7 @@ def single_band_shift_psf(
psf in the focal plane. Normalized as the input flux is 1. psf in the focal plane. Normalized as the input flux is 1.
(Note that total flux of the psf is not 1, because it is masked) (Note that total flux of the psf is not 1, because it is masked)
""" """
actuator = actuators[actuator_index]
error = np.random.normal(0, error*1e-9, actuator.shape) error = np.random.normal(0, error*1e-9, actuator.shape)
deformable_mirror.actuators = actuator + error deformable_mirror.actuators = actuator + error
wf = Wavefront(aperture, wavelength) wf = Wavefront(aperture, wavelength)
...@@ -150,7 +161,8 @@ def single_band_shift_psf( ...@@ -150,7 +161,8 @@ def single_band_shift_psf(
def single_band_psf( def single_band_psf(
wavelength: float, wavelength: float,
error: float = 0) -> np.ndarray: error: float = 0,
actuator_index: int = 1) -> np.ndarray:
"""CPIC PSF without considering the focal plane mask. """CPIC PSF without considering the focal plane mask.
Used to simulate the off-axis PSF. Used to simulate the off-axis PSF.
...@@ -166,6 +178,7 @@ def single_band_psf( ...@@ -166,6 +178,7 @@ def single_band_psf(
psf : np.ndarray psf : np.ndarray
psf in the focal plane. Normalized. The total flux is 1. psf in the focal plane. Normalized. The total flux is 1.
""" """
actuator = actuators[actuator_index]
error = np.random.normal(0, error*1e-9, actuator.shape) error = np.random.normal(0, error*1e-9, actuator.shape)
deformable_mirror.actuators = actuator + error deformable_mirror.actuators = actuator + error
wf = Wavefront(aperture, wavelength) wf = Wavefront(aperture, wavelength)
......
band: f661 band: f520
# emgain: 100 # emgain: 100
emset: 180 emset: 180
expt: 30 expt: 30
...@@ -10,6 +10,7 @@ shift: ...@@ -10,6 +10,7 @@ shift:
- 0 - 0
- 0 - 0
skybg: 20.31 skybg: 20.31
dm_volt_index: -1
target: target:
cstar: cstar:
dec: 84.2875d dec: 84.2875d
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment