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

tickets/DM-43403: fix off-axis model for full-array mode and comcam #226

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions doc/versionHistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
Version History
##################

.. _lsst.ts.wep-10.5.0:

-------------
10.5.0
-------------

* Added ``defocalOffset`` and ``batoidOffsetValue`` attributes to the ``Image`` class.
* Offset values in ``Image`` class now override ``Instrument`` defaults when not None.

.. _lsst.ts.wep-10.4.1:

-------------
Expand Down
2 changes: 1 addition & 1 deletion policy/instruments/ComCam.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ imports: policy:instruments/LsstCam.yaml
# Apply these overrides
name: LsstComCam
batoidModelName: ComCam_{band}
batoidOffsetOptic: ComCam
batoidOffsetOptic: Detector

maskParams:
M1:
Expand Down
2 changes: 2 additions & 0 deletions policy/instruments/LsstCam.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ wavelength:
z: 866.8e-9
y: 973.9e-9
batoidModelName: LSST_{band} # name used to load the Batoid model
batoidOffsetOptic: Detector # Element in Batoid model offset for defocus
batoidOffsetValue: 1.5e-3 # Size of offset in Batoid model, in meters

maskParams: # center and radius are in meters, theta in degrees
M1:
Expand Down
5 changes: 3 additions & 2 deletions python/lsst/ts/wep/estimation/danish.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,9 @@ def _estimateSingleZk(
zkStart = np.pad(zkStart, (4, 0))
offAxisCoeff = instrument.getOffAxisCoeff(
*image.fieldAngle,
image.defocalType,
image.bandLabel,
defocalType=image.defocalType,
batoidOffsetValue=image.batoidOffsetValue,
band=image.bandLabel,
jmaxIntrinsic=jmax,
return4Up=False,
)
Expand Down
10 changes: 10 additions & 0 deletions python/lsst/ts/wep/estimation/wfAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,16 @@ def estimateZk(
saveHistory,
)

# If either image has defocal offset, override default instrument value
offsets = [
img.defocalOffset
for img in (I1, I2)
if img is not None and img.defocalOffset is not None
]
if len(offsets) > 0:
instrument = instrument.copy()
instrument.defocalOffset = np.mean(offsets)

# Get the intrinsic Zernikes?
if startWithIntrinsic or returnWfDev:
zkIntrinsicI1 = instrument.getIntrinsicZernikes(
Expand Down
96 changes: 88 additions & 8 deletions python/lsst/ts/wep/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ class Image:
Note these shifts must be in the global CCS (see the note on
coordinate systems above).
(the default is an empty array, i.e. no blends)
mask : np.ndarray, optional
The image source mask that is 1 for source pixels and 0 otherwise.
Mask creation is meant to be handled by the ImageMapper class.
(the default is None)
maskBlends : np.ndarray, optional
The image blend mask that is 1 for blend pixels and 0 otherwise.
Mask creation is meant to be handled by the ImageMapper class.
(the default is None)
maskBackground : np.ndarray, optional
The image background mask that is 1 for background pixels and 0
otherwise. Mask creation is meant to be handled by the ImageMapper
class.
(the default is None)
defocalOffset : float, optional
The defocal offset of the detector when this image was taken (or
the equivalent offset if some other element, such as M2, was offset).
If not None, this value will override the default value in the
instrument when using the ImageMapper.
(the default is None)
batoidOffsetValue : float, optional
The offset of batoidOffsetOptic used to calculate off-axis
coefficients. If not None, this value will override the default value
in the instrument when using the ImageMapper.
(the default is None)
"""

def __init__(
Expand All @@ -77,18 +101,23 @@ def __init__(
bandLabel: Union[BandLabel, str] = BandLabel.REF,
planeType: Union[PlaneType, str] = PlaneType.Image,
blendOffsets: Union[np.ndarray, tuple, list, None] = None,
mask: Optional[np.ndarray] = None,
maskBlends: Optional[np.ndarray] = None,
maskBackground: Optional[np.ndarray] = None,
defocalOffset: Optional[float] = None,
batoidOffsetValue: Optional[float] = None,
) -> None:
self.image = image
self.fieldAngle = fieldAngle # type: ignore
self.defocalType = defocalType # type: ignore
self.bandLabel = bandLabel # type: ignore
self.planeType = planeType # type: ignore
self.blendOffsets = blendOffsets # type: ignore

# Set all mask variables
self._mask = None
self._maskBlends = None
self._maskBackground = None
self.mask = mask
self.maskBlends = maskBlends
self.maskBackground = maskBackground
self.defocalOffset = defocalOffset
self.batoidOffsetValue = batoidOffsetValue

@property
def image(self) -> np.ndarray:
Expand Down Expand Up @@ -162,7 +191,7 @@ def defocalType(self, value: Union[DefocalType, str]) -> None:
TypeError
The provided value is not a DefocalType Enum or string.
"""
if isinstance(value, str) or isinstance(value, DefocalType):
if isinstance(value, (str, DefocalType)):
self._defocalType = DefocalType(value)
else:
raise TypeError(
Expand Down Expand Up @@ -193,7 +222,7 @@ def bandLabel(self, value: Union[BandLabel, str, None]) -> None:
"""
if value is None or value == "":
self._bandLabel = BandLabel.REF
elif isinstance(value, str) or isinstance(value, BandLabel):
elif isinstance(value, (str, BandLabel)):
self._bandLabel = BandLabel(value)
else:
raise TypeError(
Expand All @@ -220,7 +249,7 @@ def planeType(self, value: Union[PlaneType, str]) -> None:
TypeError
The provided value is not a PlaneType Enum or string.
"""
if isinstance(value, str) or isinstance(value, PlaneType):
if isinstance(value, (str, PlaneType)):
self._planeType = PlaneType(value)
else:
raise TypeError(
Expand Down Expand Up @@ -377,6 +406,57 @@ def masks(self) -> tuple:
"""Return (self.mask, self.maskBlends, self.maskBackground)."""
return (self.mask, self.maskBlends, self.maskBackground)

@property
def defocalOffset(self) -> Union[float, None]:
"""Defocal offset of the detector when this image was taken.

If some other element was offset, such as M2, this is the equivalent
detector offset. If not None, this value will override the default
value in the instrument when using the ImageMapper.
"""
return self._defocalOffset

@defocalOffset.setter
def defocalOffset(self, value: Optional[float]) -> None:
"""Set the defocal offset of the detector when this image was taken.

If some other element was offset, such as M2, this is the equivalent
detector offset. If not None, this value will override the default
value in the instrument when using the ImageMapper.

Parameters
----------
value : float or None
"""
if value is not None:
value = np.abs(float(value))
self._defocalOffset = value

@property
def batoidOffsetValue(self) -> Union[float, None]:
"""Offset of batoidOffsetOptic used to calculate off-axis coefficients.

If not None, this value will override the default value in the
instrument when using the ImageMapper.
"""
return self._batoidOffsetValue

@batoidOffsetValue.setter
def batoidOffsetValue(self, value: Optional[float]) -> None:
"""Set the batoidOffsetValue.

This is the offset of the batoidOffsetOptic used to calculate the
off-axis coefficients for ImageMapper. If not None, this value will
override the default value in the instrument when using ImageMapper.

Parameters
----------
value : float or None
"""
if value is not None:
value = float(value)
self._batoidOffsetValue = value

def copy(self) -> Self:
"""Return a copy of the DonutImage object.

Expand Down
1 change: 1 addition & 0 deletions python/lsst/ts/wep/imageMapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def _constructForwardMap(
offAxisCoeff = self.instrument.getOffAxisCoeff(
*image.fieldAngle,
image.defocalType,
image.batoidOffsetValue,
image.bandLabel,
jmaxIntrinsic=len(zkCoeff) + 3,
)
Expand Down
Loading
Loading