Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add comcam closed loop #21

Merged
merged 3 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/versionHistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
Version History
##################

-------------
0.10.0
-------------

* Add comcam support.
* Add new comcam configuration files.

-------------
0.9.0
-------------
Expand Down
69 changes: 69 additions & 0 deletions policy/config/input/telescope/lsstComCamLargePert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
telescope:
camera: LsstComCam
file_name:
type: FormattedStr
format: ComCam_%s.yaml
items:
- *band
rotTelPos: *rtp # Set the camera rotator angle using the value defined above.
# Many kinds of perturbations are possible.
# See https://github.com/LSSTDESC/imSim/blob/main/imsim/telescope_loader.py for details
# Some examples below
perturbations:
# Perturb optics directly. Note that some of these are degenerate with the
# fea.aos_dof.dof parameters below. For the closed-loop feedback simulation, it
# probably makes more sense to use the dof parameters.
M2: # Optics to perturb
shift: [1.0e-6, 0.0, 0.0] # x,y,z Shift in meters
rotX: 4 arcsec # Rotation around x axis
Zernike: # (annular by default; you can override R_inner or R_outer though)
idx: [4, 5, 6, 7, 8] # Zernike indices
val: [4.e-7, -2.e-7, 1.0e-7, 0.4e-7, -0.9e-7] # Zernike values in meters
M3:
Zernike: # (annular by default; you can override R_inner or R_outer though)
idx: [4, 5, 6, 7, 8] # Zernike indices
val: [3.1e-7, -3.6e-7, -0.3e-7, 1.7e-7, 0.3e-7] # Zernike values in meters
# There's a whole suite of FEA perturbations available (same as ts_phosim)
# Details in the telescope_loader.py file linked above.
fea:
m1m3_gravity: # gravitational flexure of M1M3
zenith: *zenith
m1m3_temperature:
m1m3_TBulk: 0.1 # Celsius
m1m3_TxGrad: 0.01 # Kelvin/meter
m1m3_TyGrad: 0.01 # Kelvin/meter
m1m3_TzGrad: 0.01 # Kelvin/meter
m1m3_TrGrad: 0.01 # Kelvin/meter
# LUT correction to counteract m1m3_gravity
m1m3_lut:
# Note that you aren't _required_ to use the same zenith angle here as above, though
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
# it's usually a good idea.
zenith: *zenith
error: 0.05 # fractional actuator random error to apply to LUT correction.
seed: 11 # random seed for above error
m2_gravity:
zenith: *zenith
m2_temperature:
m2_TzGrad: 0.01 # Kelvin/meter
m2_TrGrad: 0.01 # Kelvin/meter
camera_gravity:
zenith: *zenith
rotation: *rtp
camera_temperature:
camera_TBulk: 0.1 # Celsius

# And finally, AOS degrees of freedom in standard order and units.
# which means:
# 0: M2 dz (mm)
# 1,2: M2 dx,dy (mm)
# 3,4: M2 rx,ry (arcsec)
# 5: camera dz (mm)
# 6,7: camera dx,dy (mm)
# 8,9: camera rx,ry (arcsec)
# 10-29: M1M3 bending modes (mm)
# 30-49: M2 bending modes (mm)

# Eval string here is compact for the demo. For simulating the closed loop, you probably
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
# will use a 50-element list here.
aos_dof:
dof: $[0.0]*50
70 changes: 70 additions & 0 deletions policy/config/input/telescope/lsstComCamNoPert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
telescope:
camera: LsstComCam
file_name:
type: FormattedStr
format: ComCam_%s.yaml
items:
- *band
rotTelPos: *rtp # Set the camera rotator angle using the value defined above.
# Many kinds of perturbations are possible.
# See https://github.com/LSSTDESC/imSim/blob/main/imsim/telescope_loader.py for details
# Some examples below
# perturbations:
# # Perturb optics directly. Note that some of these are degenerate with the
# # fea.aos_dof.dof parameters below. For the closed-loop feedback simulation, it
# # probably makes more sense to use the dof parameters.
# M2: # Optics to perturb
# shift: [1.0e-6, 0.0, 0.0] # x,y,z Shift in meters
# rotX: 4 arcsec # Rotation around x axis
# Zernike: # (annular by default; you can override R_inner or R_outer though)
# idx: [4, 6] # Zernike indices
# val: [1.e-8, 0.1e-8] # Zernike values in meters
# M3:
# Zernike:
# # coefs: $[0.0]*23 # You can also set Zernike coefs like this...
# idx: [6]
# val: [1e-6]
# There's a whole suite of FEA perturbations available (same as ts_phosim)
# Details in the telescope_loader.py file linked above.
fea:
m1m3_gravity: # gravitational flexure of M1M3
zenith: *zenith
m1m3_temperature:
m1m3_TBulk: 0.1 # Celsius
m1m3_TxGrad: 0.01 # Kelvin/meter
m1m3_TyGrad: 0.01 # Kelvin/meter
m1m3_TzGrad: 0.01 # Kelvin/meter
m1m3_TrGrad: 0.01 # Kelvin/meter
# LUT correction to counteract m1m3_gravity
m1m3_lut:
# Note that you aren't _required_ to use the same zenith angle here as above, though
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
# it's usually a good idea.
zenith: *zenith
error: 0.05 # fractional actuator random error to apply to LUT correction.
seed: 11 # random seed for above error
m2_gravity:
zenith: *zenith
m2_temperature:
m2_TzGrad: 0.01 # Kelvin/meter
m2_TrGrad: 0.01 # Kelvin/meter
camera_gravity:
zenith: *zenith
rotation: *rtp
camera_temperature:
camera_TBulk: 0.1 # Celsius

# And finally, AOS degrees of freedom in standard order and units.
# which means:
# 0: M2 dz (mm)
# 1,2: M2 dx,dy (mm)
# 3,4: M2 rx,ry (arcsec)
# 5: camera dz (mm)
# 6,7: camera dx,dy (mm)
# 8,9: camera rx,ry (arcsec)
# 10-29: M1M3 bending modes (mm)
# 30-49: M2 bending modes (mm)

# Eval string here is compact for the demo. For simulating the closed loop, you probably
# will use a 50-element list here.
aos_dof:
dof: $[0.0]*50
12 changes: 12 additions & 0 deletions policy/config/lsstComCamLargePertPointer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Default LSSTCam configuration files
input:
atm_psf: '{TS_IMSIM_DIR}/policy/config/input/atm_psf/atmPsfDefault.yaml'
sky_model: '{TS_IMSIM_DIR}/policy/config/input/sky_model/skyModelDefault.yaml'
telescope: '{TS_IMSIM_DIR}/policy/config/input/telescope/lsstComCamLargePert.yaml'
vignetting: '{TS_IMSIM_DIR}/policy/config/input/vignetting/lsstCamDefault.yaml'
gal: '{TS_IMSIM_DIR}/policy/config/gal/starDefault.yaml'
image: '{TS_IMSIM_DIR}/policy/config/image/lsstCamDefault.yaml'
psf: '{TS_IMSIM_DIR}/policy/config/psf/psfDefault.yaml'
stamp: '{TS_IMSIM_DIR}/policy/config/stamp/lsstCamDefault.yaml'
output: '{TS_IMSIM_DIR}/policy/config/output/lsstComCamDefault.yaml'
opd: '{TS_IMSIM_DIR}/policy/config/opd/lsstCamDefault.yaml'
12 changes: 12 additions & 0 deletions policy/config/lsstComCamNoPertPointer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Default LSSTCam configuration files
input:
atm_psf: '{TS_IMSIM_DIR}/policy/config/input/atm_psf/atmPsfDefault.yaml'
sky_model: '{TS_IMSIM_DIR}/policy/config/input/sky_model/skyModelDefault.yaml'
telescope: '{TS_IMSIM_DIR}/policy/config/input/telescope/lsstComCamNoPert.yaml'
vignetting: '{TS_IMSIM_DIR}/policy/config/input/vignetting/lsstCamDefault.yaml'
gal: '{TS_IMSIM_DIR}/policy/config/gal/starDefault.yaml'
image: '{TS_IMSIM_DIR}/policy/config/image/lsstCamDefault.yaml'
psf: '{TS_IMSIM_DIR}/policy/config/psf/psfDefault.yaml'
stamp: '{TS_IMSIM_DIR}/policy/config/stamp/lsstCamDefault.yaml'
output: '{TS_IMSIM_DIR}/policy/config/output/lsstComCamDefault.yaml'
opd: '{TS_IMSIM_DIR}/policy/config/opd/lsstCamDefault.yaml'
46 changes: 46 additions & 0 deletions policy/config/output/lsstComCamDefault.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
output:
type: LSST_CCD
nproc: 9 # Change this to work on multiple CCDs at once.
nfiles: 9 # Comcam

header:
mjd: *mjd
seqnum: *seqnum

camera: LsstComCam

exptime: $exptime

cosmic_ray_rate: 0.0 # The rate of cosmic rays per second in a sensor.

det_num:
type: List
items: $list(range(9))


file_name:
type: FormattedStr
format : raw_%s-%1d-%s-%s-det%03d.fits.fz
items:
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
- *obsid
- 0 # snap
- *band
- $det_name # A value stored in the dict by LSST_CCD
- "@output.det_num"

readout:
# Convert from e-image to realized amp images
readout_time: 2.
dark_current: 0.02
bias_level: 1000.
pcti: 1.e-6
scti: 1.e-6
file_name:
type: FormattedStr
format : amp_%s-%1d-%s-%s-det%03d.fits.fz
items:
- *obsid
- 0
- *band
- $det_name
- "@output.det_num"
50 changes: 39 additions & 11 deletions python/lsst/ts/imsim/closed_loop_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def _set_sky_sim_based_on_opd_field_pos(
)

opd_metr = OpdMetrology()
if inst_name in ["lsst", "lsstfam"]:
if inst_name in ["lsst", "lsstfam", "comcam"]:
field_x, field_y = list(), list()
camera = get_camera(inst_name)
for name in self.get_sensor_name_list_of_fields(inst_name):
Expand Down Expand Up @@ -342,6 +342,8 @@ def get_cam_type_and_inst_name(self, inst: str) -> tuple[CamType, str]:
return CamType.LsstCam, "lsst"
elif inst == "lsstfam":
return CamType.LsstFamCam, "lsstfam"
elif inst == "comcam":
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
return CamType.ComCam, "comcam"
else:
raise ValueError(f"This instrument ({inst}) is not supported.")

Expand Down Expand Up @@ -505,7 +507,7 @@ def _run_sim(
turn_off_sky_background=turn_off_sky_background,
turn_off_atmosphere=turn_off_atmosphere,
)
elif cam_type == CamType.LsstFamCam:
elif cam_type in [CamType.LsstFamCam, CamType.ComCam]:
for focus_z in [-1.5, 1.5]:
obs_metadata.seq_num += 1
obs_metadata.focus_z = focus_z
Expand All @@ -529,7 +531,7 @@ def _run_sim(
)

if self.use_ccd_img:
if cam_type in [CamType.LsstCam, CamType.LsstFamCam]:
if cam_type in [CamType.LsstCam, CamType.LsstFamCam, CamType.ComCam]:
list_of_wf_err = self._calc_wf_err_from_img(
obs_metadata,
butler_root_path=butler_root_path,
Expand Down Expand Up @@ -692,7 +694,7 @@ def _generate_images(
self.imsim_cmpt.write_yaml_and_run_imsim(
imsim_config_path, imsim_config_yaml
)
elif inst_name == "lsstfam":
elif inst_name in ["lsstfam", "comcam"]:
if self.use_ccd_img:
# Run once for OPD
imsim_opd_config_path = os.path.join(
Expand Down Expand Up @@ -836,7 +838,10 @@ def run_wep(
estimation pipeline for each sensor.
"""

butler_inst_name = "Cam"
if inst_name in ["lsst", "lsstfam"]:
butler_inst_name = "Cam"
elif inst_name == "comcam":
butler_inst_name = "ComCam"
if pipeline_file is None:
pipeline_yaml = f"{inst_name}Pipeline.yaml"
pipeline_yaml_path = os.path.join(butler_root_path, pipeline_yaml)
Expand Down Expand Up @@ -875,6 +880,14 @@ def run_wep(
f"--register-dataset-types --output-run ts_imsim_{seq_num} -p {pipeline_yaml_path} -d "
f'"visit.seq_num IN ({seq_num-1}, {seq_num})" -j {num_pro}'
)
elif inst_name == "comcam":
runProgram(
f"pipetask run -b {butler_root_path} "
f"-i refcats,LSST{butler_inst_name}/raw/all,LSST{butler_inst_name}/calib/unbounded "
f"--instrument lsst.obs.lsst.Lsst{butler_inst_name} "
f"--register-dataset-types --output-run ts_imsim_{seq_num} -p {pipeline_yaml_path} -d "
f'"visit.seq_num IN ({seq_num-1}, {seq_num})" -j {num_pro}'
)

# Need to redefine butler because the database changed.
butler = dafButler.Butler(butler_root_path)
Expand Down Expand Up @@ -933,7 +946,10 @@ def write_wep_configuration(
Filter type name: ref (or ''), u, g, r, i, z, or y.
"""

butler_inst_name = "Cam"
if inst_name in ["lsst", "lsstfam"]:
butler_inst_name = "Cam"
elif inst_name == "comcam":
butler_inst_name = "ComCam"

# Remap reference filter
filter_type_name = self.map_filter_ref_to_g(filter_type_name)
Expand Down Expand Up @@ -1128,9 +1144,14 @@ def generate_butler(self, butler_root_path: str, inst_name: str) -> None:

runProgram(f"butler create {butler_root_path}")

self.log.debug("Registering LsstCam")
if inst_name in ["lsst", "lsstfam"]:
butler_inst_name = "Cam"
elif inst_name == "comcam":
butler_inst_name = "ComCam"

self.log.debug(f"Registering Lsst{butler_inst_name}")
runProgram(
f"butler register-instrument {butler_root_path} lsst.obs.lsst.LsstCam"
f"butler register-instrument {butler_root_path} lsst.obs.lsst.Lsst{butler_inst_name}"
)

def generate_ref_catalog(
Expand Down Expand Up @@ -1204,10 +1225,17 @@ def ingest_data(self, butler_root_path: str, inst_name: str) -> None:
output_img_dir = self.imsim_cmpt.output_img_dir
files = " ".join(glob(os.path.join(output_img_dir, "amp*")))

if inst_name in ["lsst", "lsstfam"]:
if inst_name in ["lsst", "lsstfam", "comcam"]:
runProgram(f"butler ingest-raws {butler_root_path} {files}")

runProgram(f"butler define-visits {butler_root_path} lsst.obs.lsst.LsstCam")
if inst_name in ["lsst", "lsstfam"]:
butler_inst_name = "Cam"
elif inst_name == "comcam":
butler_inst_name = "ComCam"

runProgram(
f"butler define-visits {butler_root_path} lsst.obs.lsst.Lsst{butler_inst_name}"
)

def erase_directory_content(self, target_dir: str) -> None:
"""Erase the directory content.
Expand Down Expand Up @@ -1244,7 +1272,7 @@ def set_default_parser(parser: ArgumentParser) -> ArgumentParser:
"--inst",
type=str,
default="lsst",
help="Instrument to use: currently lsst or lsstfam. (default: lsst)",
help="Instrument to use: currently lsst, lsstfam, comcam. (default: lsst)",
)

parser.add_argument(
Expand Down
7 changes: 4 additions & 3 deletions python/lsst/ts/imsim/opd_metrology.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def set_wgt_and_field_xy_of_gq(self, inst_name: str) -> None:
----------
inst_name : `str`
Instrument name.
Valid options are 'lsst' or 'lsstfam.
Valid options are 'lsst', 'lsstfam', or 'comcam'.

Raises
------
Expand Down Expand Up @@ -150,9 +150,11 @@ def set_wgt_and_field_xy_of_gq(self, inst_name: str) -> None:
# Normalize weights
self.wt = wgt_values / np.sum(wgt_values)

camera = get_camera(inst_name)
if inst_name == "lsstfam":
camera = get_camera(inst_name)
self.sensor_ids = np.arange(189)
elif inst_name == "comcam":
self.sensor_ids = np.arange(9)
else:
raise ValueError(f"Instrument {inst_name} is not supported in OPD mode.")

Expand Down Expand Up @@ -333,7 +335,6 @@ def calc_gq_value(self, value_list: list[float] | np.ndarray) -> float:
ValueError
Length of wt ratio != length of value list.
"""

# Check the lengths of weighting ratio and value list are the same
if len(self.wt) != len(value_list):
raise ValueError("Length of wt ratio != length of value list.")
Expand Down
Loading
Loading