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

Move rotations of donut stamps from calculate step to save donutStamps. #203

Merged
merged 4 commits into from
Oct 17, 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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ setup -k -r .

To learn more about how to run the pipeline tasks associated with WEP we have a series of Jupyter Notebooks available in the AOS section of the `ts_analysis_notebooks` [repository](https://github.com/lsst-ts/ts_analysis_notebooks).

## Deprecation of support for Phosim and ts_phosim

Starting with v8.0 running the AOS closed loop with Phosim and `ts_phosim` will no longer work.
We are moving to support imSim and `ts_imsim` exclusively moving forward.
There are changes in the orientation of the DonutStamps in v8.0+ that will not work with the `ts_phosim` closed loop.

## Test Gen 3 Repository

In the folder `tests/testData/` there is a test repository for tasks that run with the Gen 3 DM middleware.
Expand Down
14 changes: 12 additions & 2 deletions doc/versionHistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
##################
Version History
##################

.. _lsst.ts.wep-8.0.0:

-------------
8.0.0
-------------

* Save all DonutStamps with images aligned with focal plane science sensors.
* This version will break compatibility in the closed loop with Phosim and ts_phosim going forward.


.. _lsst.ts.wep-7.0.1:

-------------
Expand All @@ -13,7 +24,6 @@ Version History

* Fix generateDonutDirectDetect when doDonutSelection is not run.


.. _lsst.ts.wep-7.0.0:

-------------
Expand All @@ -28,7 +38,7 @@ Version History
6.4.12
-------------

* Update ts_pre_commit_config with ruff.
* Update ts_pre_commit_config with ruff.

.. _lsst.ts.wep-6.4.11:

Expand Down
47 changes: 24 additions & 23 deletions python/lsst/ts/wep/task/calcZernikesTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
)
from lsst.ts.wep.wfEstimator import WfEstimator
from lsst.utils.timer import timeMethod
from scipy.ndimage import rotate


class CalcZernikesTaskConnections(
Expand Down Expand Up @@ -116,6 +115,7 @@ class CalcZernikesTaskConfig(
dtype=bool,
default=True,
optional=True,
deprecated="This field is no longer used. Will be removed after the end of October 2023.",
)


Expand All @@ -135,8 +135,6 @@ def __init__(self, **kwargs):
# for the detector.
self.combineZernikes = self.config.combineZernikes
self.makeSubtask("combineZernikes")
# Specify whether to transpose images
self.transposeImages = self.config.transposeImages
# Specify optical model
self.opticalModel = self.config.opticalModel
# Set up instrument configuration dict
Expand Down Expand Up @@ -234,38 +232,41 @@ def estimateZernikes(self, donutStampsExtra, donutStampsIntra):
eulerZExtra = -detectorExtra.getOrientation().getYaw().asDegrees()
eulerZIntra = -detectorIntra.getOrientation().getYaw().asDegrees()

# NOTE: TS_WEP expects these images to be transposed
# TODO: Look into this
blendOffsetsExtra = self.calcBlendOffsets(donutExtra, eulerZExtra)
blendOffsetsIntra = self.calcBlendOffsets(donutIntra, eulerZIntra)

if self.transposeImages:
imageExtra = rotate(
donutExtra.stamp_im.getImage().getArray(), eulerZExtra
).T
imageIntra = rotate(
donutIntra.stamp_im.getImage().getArray(), eulerZIntra
).T
else:
imageExtra = rotate(
donutExtra.stamp_im.getImage().getArray(), eulerZExtra
)
imageIntra = rotate(
donutIntra.stamp_im.getImage().getArray(), eulerZIntra
)
# Below we transform the image array and coordinates from the DVCS
# (Data Visualization Coordinate System) to the
# ZCS (Zemax Coordinate System). More information about these
# coordinate systems is available here: sitcomtn-003.lsst.io.
# This transformation below incorporates two different coordinate
# conversions: 1) DVCS to CCS is a transpose and 2) CCS to ZCS is
# an x -> -x conversion that we can apply as a left-right flip.
# In a future update to ts_ofc we will update the sensitivity
# matrix to use the CCS and we can then remove the left-right
# flip. That is why the current version keeps this as a
# two part transformation.
#
# DVCS CCS ZCS
# x y y
# ^ ^ ^
# | | |
# | | |
# | | |
# |----------> y |----------> x x <----------|

wfEsti.setImg(
fieldXYExtra,
np.array([-fieldXYExtra[1], fieldXYExtra[0]]),
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
DefocalType.Extra,
filterLabel=getFilterTypeFromBandLabel(donutExtra.bandpass),
image=imageExtra,
image=np.fliplr(donutExtra.stamp_im.image.array.T),
blendOffsets=blendOffsetsExtra.tolist(),
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
)
wfEsti.setImg(
fieldXYIntra,
np.array([-fieldXYIntra[1], fieldXYIntra[0]]),
DefocalType.Intra,
filterLabel=getFilterTypeFromBandLabel(donutIntra.bandpass),
image=imageIntra,
image=np.fliplr(donutIntra.stamp_im.image.array.T),
blendOffsets=blendOffsetsIntra.tolist(),
)
wfEsti.reset()
Expand Down
18 changes: 15 additions & 3 deletions python/lsst/ts/wep/task/cutOutDonutsBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@
from lsst.ts.wep.utils import (
DonutTemplateType,
createInstDictFromConfig,
getCameraFromButlerName,
getCamTypeFromButlerName,
)
from scipy.ndimage import binary_dilation, shift
from scipy.ndimage import binary_dilation, rotate, shift
from scipy.signal import correlate


Expand Down Expand Up @@ -439,7 +440,7 @@ def cutOutStamps(self, exposure, donutCatalog, defocalType, cameraName):
)
xCornerList.append(xCorner)
yCornerList.append(yCorner)
finalCutout = exposure[finalBBox]
finalCutout = exposure[finalBBox].clone()

# Save MaskedImage to stamp
finalStamp = finalCutout.getMaskedImage()
Expand Down Expand Up @@ -499,7 +500,6 @@ def cutOutStamps(self, exposure, donutCatalog, defocalType, cameraName):
donutStamp.makeMasks(
inst, self.opticalModel, boundaryT, maskScalingFactorLocal
)
donutStamp.stamp_im.setMask(donutStamp.mask_comp)

# Create shifted mask from non-blended mask
if (self.multiplyMask is True) and blendExists:
Expand All @@ -522,6 +522,18 @@ def cutOutStamps(self, exposure, donutCatalog, defocalType, cameraName):
shiftedMask -= 1
donutStamp.stamp_im.image.array *= shiftedMask

camera = getCameraFromButlerName(cameraName)
detectorInfo = camera.get(detectorName)

# Rotate sensors to line up with the science sensors in the
# focal plane.
eulerZ = -detectorInfo.getOrientation().getYaw().asDegrees()
donutStamp.stamp_im.image.array = rotate(
donutStamp.stamp_im.image.array, eulerZ
)

donutStamp.stamp_im.setMask(donutStamp.mask_comp)

finalStamps.append(donutStamp)

catalogLength = len(donutCatalog)
Expand Down
17 changes: 7 additions & 10 deletions python/lsst/ts/wep/task/donutStamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@
import lsst.afw.image as afwImage
import lsst.afw.table as afwTable
import lsst.geom
import lsst.obs.lsst as obs_lsst
import numpy as np
from lsst.afw.cameraGeom import FIELD_ANGLE, PIXELS
from lsst.meas.algorithms.stamps import AbstractStamp
from lsst.ts.wep.cwfs.compensableImage import CompensableImage
from lsst.ts.wep.utils import DefocalType, FilterType, getFilterTypeFromBandLabel
from lsst.ts.wep.utils import (
DefocalType,
FilterType,
getCameraFromButlerName,
getFilterTypeFromBandLabel,
)


@dataclass
Expand Down Expand Up @@ -185,14 +189,7 @@ def getCamera(self):
The camera is not supported.
"""

if self.cam_name == "LSSTCam":
return obs_lsst.LsstCam().getCamera()
elif self.cam_name == "LSSTComCam":
return obs_lsst.LsstComCam().getCamera()
elif self.cam_name == "LATISS":
return obs_lsst.Latiss.getCamera()
else:
raise ValueError(f"Camera {self.cam_name} is not supported.")
return getCameraFromButlerName(self.cam_name)

def calcFieldXY(self):
"""
Expand Down
34 changes: 34 additions & 0 deletions python/lsst/ts/wep/utils/taskUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
"runProgram",
"writePipetaskCmd",
"writeCleanUpRepoCmd",
"getCameraFromButlerName",
]

import os
import subprocess

import lsst.obs.lsst as obs_lsst


def runProgram(command, binDir=None, argstring=None):
"""Run the program w/o arguments.
Expand Down Expand Up @@ -131,3 +134,34 @@ def writeCleanUpRepoCmd(repoDir, runName):
cleanUpCmd += f"{repoDir} {runName} --no-confirm"

return cleanUpCmd


def getCameraFromButlerName(camName):
"""
Get the proper camera object for the donuts.

Parameters
----------
camName : str
Name of instrument using butler convention. Available instruments
are LSSTCam, LSSTComCam, and LATISS.

Returns
-------
`lsst.afw.cameraGeom.Camera`
Camera object for the exposures.

Raises
------
`ValueError`
The camera is not supported.
"""

if camName == "LSSTCam":
return obs_lsst.LsstCam().getCamera()
elif camName == "LSSTComCam":
return obs_lsst.LsstComCam().getCamera()
elif camName == "LATISS":
return obs_lsst.Latiss.getCamera()
else:
raise ValueError(f"Camera {camName} is not supported.")
76 changes: 38 additions & 38 deletions tests/task/test_calcZernikesTaskCwfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,25 +158,25 @@ def testEstimateCornerZernikes(self):
).combinedZernikes
trueZernCoeffR04 = np.array(
[
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
-0.71201408,
1.12248525,
0.77794367,
-0.04085477,
-0.05272933,
0.16054277,
0.081405,
-0.04382461,
-0.04830676,
-0.06218882,
0.10246469,
0.0197683,
0.007953,
0.00668697,
-0.03570788,
-0.03020376,
0.0039522,
0.04793133,
-0.00804605,
-0.35353452,
-0.07365128,
0.62222451,
-0.06206281,
-0.09065757,
0.21722746,
-0.20491936,
0.00849322,
-0.01150489,
0.02599147,
-0.00150702,
-0.14100845,
0.02294787,
0.02284791,
0.02116483,
-0.02537743,
0.01866772,
0.01653037,
-0.00552862,
]
)
# Make sure the total rms error is less than 0.35 microns off
Expand All @@ -198,25 +198,25 @@ def testEstimateCornerZernikes(self):
).combinedZernikes
trueZernCoeffR40 = np.array(
[
-0.6535694,
1.00838499,
0.55968811,
-0.08899825,
0.00173607,
0.04133107,
-0.10913093,
-0.04363778,
-0.03149601,
-0.04941225,
0.09980538,
0.03704486,
-0.00210766,
0.01737253,
0.01727539,
0.01278011,
0.01212878,
0.03876888,
-0.00559142,
-3.83610201e-01,
-2.06528254e-01,
5.42893431e-01,
7.74255848e-02,
3.40529812e-02,
5.45565149e-02,
8.65849308e-02,
1.75029212e-02,
-1.40149246e-04,
4.11223127e-02,
-2.42644902e-03,
-1.52392233e-01,
-1.24547354e-02,
-2.33075716e-02,
7.35477674e-04,
1.93518814e-02,
-3.65768735e-03,
4.12718699e-02,
-6.93386734e-03,
]
)
# Make sure the total rms error is less than 0.35 microns off
Expand Down
4 changes: 3 additions & 1 deletion tests/task/test_cutOutDonutsBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ def testCutOutStamps(self):
lsst.geom.Extent2I(160),
)
expCutOut = exposure[stampBBox].image.array
np.testing.assert_array_equal(donutStamps[0].stamp_im.image.array, expCutOut)
np.testing.assert_array_almost_equal(
donutStamps[0].stamp_im.image.array, expCutOut
)

def testCutOutStampsBlended(self):
exposure = self.butler.get(
Expand Down
3 changes: 2 additions & 1 deletion tests/task/test_cutOutDonutsCwfsTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import os
from copy import copy

import lsst.utils.tests
from lsst.daf import butler as dafButler
Expand Down Expand Up @@ -172,7 +173,7 @@ def testTaskRunNormal(self):

# Test normal behavior
taskOut = self.task.run(
[exposureIntra, exposureExtra],
[copy(exposureIntra), copy(exposureExtra)],
[donutCatalogExtra, donutCatalogIntra],
camera,
)
Expand Down
Loading