LSST Applications g1653933729+34a971ddd9,g1a997c3884+34a971ddd9,g28da252d5a+e9c12036e6,g2bbee38e9b+387d105147,g2bc492864f+387d105147,g2ca4be77d2+2af33ed832,g2cdde0e794+704103fe75,g3156d2b45e+6e87dc994a,g347aa1857d+387d105147,g35bb328faa+34a971ddd9,g3a166c0a6a+387d105147,g3bc1096a96+da0d0eec6b,g3e281a1b8c+8ec26ec694,g4005a62e65+ba0306790b,g414038480c+9f5be647b3,g41af890bb2+260fbe2614,g5065538af8+ba676e4b71,g5a0bb5165c+019e928339,g717e5f8c0f+90540262f6,g80478fca09+bbe9b7c29a,g8204df1d8d+90540262f6,g82479be7b0+c8d705dbd9,g858d7b2824+90540262f6,g9125e01d80+34a971ddd9,g91f4dbe722+fd1343598d,ga5288a1d22+cbf2f5b209,gae0086650b+34a971ddd9,gb58c049af0+ace264a4f2,gc28159a63d+387d105147,gcf0d15dbbd+c403bb023e,gd6b7c0dfd1+f7139e6704,gda6a2b7d83+c403bb023e,gdaeeff99f8+7774323b41,ge2409df99d+d3bbf40f76,ge33fd446bb+90540262f6,ge79ae78c31+387d105147,gf0baf85859+890af219f9,gf5289d68f6+d7e5a322af,w.2024.37
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Static Public Attributes | Protected Member Functions | Protected Attributes | Static Protected Attributes | List of all members
lsst.pipe.tasks.peekExposure.PeekExposureTask Class Reference
Inheritance diagram for lsst.pipe.tasks.peekExposure.PeekExposureTask:

Public Member Functions

 __init__ (self, Any config, *Any display=None, **Any kwargs)
 
float getDonutDiameter (self, afwImage.Exposure exposure)
 
pipeBase.Struct run (self, afwImage.Exposure exposure, *bool doDisplay=False, bool doDisplayIndices=False, str mode="auto", int|None binSize=None, float|None donutDiameter=None)
 
tuple[str, int, afwTable.SourceCatalogrunPeek (self, afwImage.Exposure exposure, str mode, float donutDiameter, int|None binSize=None)
 
astropy.table.Table transformTable (self, int binSize, afwTable.SourceCatalog binnedSourceCat)
 
tuple[int, geom.Point2D, afwGeom.QuadrupolegetBrightest (self, afwTable.SourceCatalog binnedSourceCat, int binSize, npt.NDArray[np.bool_] goodSourceMask)
 
afwGeom.Quadrupole getPsfShape (self, afwTable.SourceCatalog binnedSourceCat, int binSize, npt.NDArray[np.bool_] goodSourceMask)
 
tuple[list[afwGeom.Quadrupole], list[afwGeom.Quadrupole]] transformShapes (self, afwGeom.Quadrupole shapes, afwImage.Exposure exposure, int binSize)
 
None updateDisplay (self, afwImage.Exposure exposure, int binSize, afwTable.SourceCatalog binnedSourceCat, int maxFluxIdx, bool doDisplayIndices)
 

Static Public Attributes

 ConfigClass = PeekExposureTaskConfig
 
PeekExposureTaskConfig config
 
PeekDonutTask donut
 
PeekPhotoTask photo
 
PeekSpecTask spec
 

Protected Member Functions

pipeBase.Struct _run (self, afwImage.Exposure exposure, bool doDisplay, bool doDisplayIndices, str mode, int|None binSize, float|None donutDiameter)
 

Protected Attributes

 _display
 

Static Protected Attributes

str _DefaultName = "peekExposureTask"
 

Detailed Description

Peek at exposure to quickly detect and measure both the brightest
source in the image, and a set of sources representative of the
exposure's overall image quality.

Parameters
----------
config : `lsst.summit.utils.peekExposure.PeekExposureTaskConfig`
    Configuration for the task.
display : `lsst.afw.display.Display`, optional
    For displaying the exposure and sources.

Notes
-----
The basic philosophy of PeekExposureTask is to:
1) Classify exposures based on metadata into 'donut', 'spec', or 'photo'.
2) Run PeekTask on the exposure through a wrapper with class specific
modifications.
3) Try only to branch in the code based on the metadata, and not on the
   data itself.  This avoids problematic discontinuities in measurements.

The main knobs we fiddle with based on the classification are:
    - Detection threshold
    - Minimum number of pixels for a detection
    - Binning of the image
    - Installed PSF size

Definition at line 742 of file peekExposure.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.pipe.tasks.peekExposure.PeekExposureTask.__init__ ( self,
Any config,
*Any display = None,
**Any kwargs )

Definition at line 777 of file peekExposure.py.

777 def __init__(self, config: Any, *, display: Any = None, **kwargs: Any):
778 super().__init__(config=config, **kwargs)
779
780 self.makeSubtask("donut")
781 self.makeSubtask("photo")
782 self.makeSubtask("spec")
783
784 self._display = display
785

Member Function Documentation

◆ _run()

pipeBase.Struct lsst.pipe.tasks.peekExposure.PeekExposureTask._run ( self,
afwImage.Exposure exposure,
bool doDisplay,
bool doDisplayIndices,
str mode,
int | None binSize,
float | None donutDiameter )
protected
The actual run method, called by run().

Definition at line 905 of file peekExposure.py.

913 ) -> pipeBase.Struct:
914 """The actual run method, called by run()."""
915 # If image is ~large, then use a subsampling of the image for
916 # speedy median/mode estimates.
917 arr = exposure.getMaskedImage().getImage().array
918 sampling = 1
919 if arr.size > 250_000:
920 sampling = int(np.floor(np.sqrt(arr.size / 250_000)))
921 pixelMedian = np.nanmedian(arr[::sampling, ::sampling])
922 pixelMode = _estimateMode(arr[::sampling, ::sampling])
923
924 if donutDiameter is None:
925 donutDiameter = self.getDonutDiameter(exposure)
926
927 mode, binSize, binnedSourceCat = self.runPeek(exposure, mode, donutDiameter, binSize)
928
929 table = self.transformTable(binSize, binnedSourceCat)
930
931 match mode:
932 case "donut":
933 goodSourceMask = self.donut.getGoodSources(binnedSourceCat)
934 case "spec":
935 goodSourceMask = self.spec.getGoodSources(binnedSourceCat)
936 case "photo":
937 goodSourceMask = self.photo.getGoodSources(binnedSourceCat)
938
939 # prepare output variables
940 maxFluxIdx, brightCentroid, brightShape = self.getBrightest(binnedSourceCat, binSize, goodSourceMask)
941 psfShape = self.getPsfShape(binnedSourceCat, binSize, goodSourceMask)
942
943 equatorialShapes, altAzShapes = self.transformShapes([brightShape, psfShape], exposure, binSize)
944
945 if doDisplay:
946 self.updateDisplay(exposure, binSize, binnedSourceCat, maxFluxIdx, doDisplayIndices)
947
948 return pipeBase.Struct(
949 mode=mode,
950 binSize=binSize,
951 binnedSourceCat=binnedSourceCat,
952 table=table,
953 brightestIdx=maxFluxIdx,
954 brightestCentroid=brightCentroid,
955 brightestPixelShape=brightShape,
956 brightestEquatorialShape=equatorialShapes[0],
957 brightestAltAzShape=altAzShapes[0],
958 psfPixelShape=psfShape,
959 psfEquatorialShape=equatorialShapes[1],
960 psfAltAzShape=altAzShapes[1],
961 pixelMedian=pixelMedian,
962 pixelMode=pixelMode,
963 )
964

◆ getBrightest()

tuple[int, geom.Point2D, afwGeom.Quadrupole] lsst.pipe.tasks.peekExposure.PeekExposureTask.getBrightest ( self,
afwTable.SourceCatalog binnedSourceCat,
int binSize,
npt.NDArray[np.bool_] goodSourceMask )
Find the brightest source in the catalog.

Parameters
----------
binnedSourceCat : `lsst.afw.table.SourceCatalog`
    Source catalog from the binned exposure.
binSize : `int`
    Binning factor used.
goodSourceMask : `numpy.ndarray`
    Boolean array indicating which sources are good.

Returns
-------
maxFluxIdx : `int`
    Index of the brightest source in the catalog.
brightCentroid : `lsst.geom.Point2D`
    Centroid of the brightest source (unbinned coords).
brightShape : `lsst.afw.geom.Quadrupole`
    Shape of the brightest source (unbinned coords).

Definition at line 1082 of file peekExposure.py.

1084 ) -> tuple[int, geom.Point2D, afwGeom.Quadrupole]:
1085 """Find the brightest source in the catalog.
1086
1087 Parameters
1088 ----------
1089 binnedSourceCat : `lsst.afw.table.SourceCatalog`
1090 Source catalog from the binned exposure.
1091 binSize : `int`
1092 Binning factor used.
1093 goodSourceMask : `numpy.ndarray`
1094 Boolean array indicating which sources are good.
1095
1096 Returns
1097 -------
1098 maxFluxIdx : `int`
1099 Index of the brightest source in the catalog.
1100 brightCentroid : `lsst.geom.Point2D`
1101 Centroid of the brightest source (unbinned coords).
1102 brightShape : `lsst.afw.geom.Quadrupole`
1103 Shape of the brightest source (unbinned coords).
1104 """
1105 fluxes = np.array([source.getApInstFlux() for source in binnedSourceCat])
1106 idxs = np.arange(len(binnedSourceCat))
1107
1108 good = goodSourceMask & np.isfinite(fluxes)
1109
1110 if np.sum(good) == 0:
1111 maxFluxIdx = IDX_SENTINEL
1112 brightCentroid = Point2D(np.nan, np.nan)
1113 brightShape = Quadrupole(np.nan, np.nan, np.nan)
1114 return maxFluxIdx, brightCentroid, brightShape
1115
1116 fluxes = fluxes[good]
1117 idxs = idxs[good]
1118 maxFluxIdx = idxs[np.nanargmax(fluxes)]
1119 brightest = binnedSourceCat[maxFluxIdx]
1120
1121 # Convert binned coordinates back to original unbinned
1122 # coordinates
1123 brightX, brightY = brightest.getCentroid()
1124 brightX = binSize * brightX + (binSize - 1) / 2
1125 brightY = binSize * brightY + (binSize - 1) / 2
1126 brightCentroid = Point2D(brightX, brightY)
1127 brightIXX = brightest.getIxx() * binSize**2
1128 brightIXY = brightest.getIxy() * binSize**2
1129 brightIYY = brightest.getIyy() * binSize**2
1130 brightShape = Quadrupole(brightIXX, brightIYY, brightIXY)
1131
1132 return maxFluxIdx, brightCentroid, brightShape
1133
An ellipse core with quadrupole moments as parameters.
Definition Quadrupole.h:47

◆ getDonutDiameter()

float lsst.pipe.tasks.peekExposure.PeekExposureTask.getDonutDiameter ( self,
afwImage.Exposure exposure )
Estimate donut diameter from exposure metadata.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to estimate donut diameter for.

Returns
-------
donutDiameter : `float`
    Estimated donut diameter in pixels.

Definition at line 786 of file peekExposure.py.

786 def getDonutDiameter(self, exposure: afwImage.Exposure) -> float:
787 """Estimate donut diameter from exposure metadata.
788
789 Parameters
790 ----------
791 exposure : `lsst.afw.image.Exposure`
792 Exposure to estimate donut diameter for.
793
794 Returns
795 -------
796 donutDiameter : `float`
797 Estimated donut diameter in pixels.
798 """
799 visitInfo = exposure.getInfo().getVisitInfo()
800 focusZ = visitInfo.focusZ
801 instrumentLabel = visitInfo.instrumentLabel
802
803 match instrumentLabel:
804 case "LATISS":
805 focusZ *= 41 # magnification factor
806 fratio = 18.0
807 case "LSSTCam" | "ComCam" | "LSSTComCamSim":
808 fratio = 1.234
809 case _:
810 raise ValueError(f"Unknown instrument label: {instrumentLabel}")
811 # AuxTel/ComCam/LSSTCam all have 10 micron pixels (= 10e-3 mm)
812 donutDiameter = abs(focusZ) / fratio / 10e-3
813 self.log.info(f"{focusZ=} mm")
814 self.log.info(f"donutDiameter = {donutDiameter} pixels")
815 return donutDiameter
816

◆ getPsfShape()

afwGeom.Quadrupole lsst.pipe.tasks.peekExposure.PeekExposureTask.getPsfShape ( self,
afwTable.SourceCatalog binnedSourceCat,
int binSize,
npt.NDArray[np.bool_] goodSourceMask )
Estimate the modal PSF shape from the sources.

Parameters
----------
binnedSourceCat : `lsst.afw.table.SourceCatalog`
    Source catalog from the binned exposure.
binSize : `int`
    Binning factor used.
goodSourceMask : `numpy.ndarray`
    Boolean array indicating which sources are good.

Returns
-------
psfShape : `lsst.afw.geom.Quadrupole`
    Estimated PSF shape (unbinned coords).

Definition at line 1134 of file peekExposure.py.

1136 ) -> afwGeom.Quadrupole:
1137 """Estimate the modal PSF shape from the sources.
1138
1139 Parameters
1140 ----------
1141 binnedSourceCat : `lsst.afw.table.SourceCatalog`
1142 Source catalog from the binned exposure.
1143 binSize : `int`
1144 Binning factor used.
1145 goodSourceMask : `numpy.ndarray`
1146 Boolean array indicating which sources are good.
1147
1148 Returns
1149 -------
1150 psfShape : `lsst.afw.geom.Quadrupole`
1151 Estimated PSF shape (unbinned coords).
1152 """
1153 fluxes = np.array([source.getApInstFlux() for source in binnedSourceCat])
1154 idxs = np.arange(len(binnedSourceCat))
1155
1156 good = goodSourceMask & np.isfinite(fluxes)
1157
1158 if np.sum(good) == 0:
1159 return Quadrupole(np.nan, np.nan, np.nan)
1160
1161 fluxes = fluxes[good]
1162 idxs = idxs[good]
1163
1164 psfIXX = _estimateMode(np.array([source.getIxx() for source in binnedSourceCat])[goodSourceMask])
1165 psfIYY = _estimateMode(np.array([source.getIyy() for source in binnedSourceCat])[goodSourceMask])
1166 psfIXY = _estimateMode(np.array([source.getIxy() for source in binnedSourceCat])[goodSourceMask])
1167
1168 return Quadrupole(
1169 psfIXX * binSize**2,
1170 psfIYY * binSize**2,
1171 psfIXY * binSize**2,
1172 )
1173

◆ run()

pipeBase.Struct lsst.pipe.tasks.peekExposure.PeekExposureTask.run ( self,
afwImage.Exposure exposure,
*bool doDisplay = False,
bool doDisplayIndices = False,
str mode = "auto",
int | None binSize = None,
float | None donutDiameter = None )
Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure at which to peek.
doDisplay : `bool`, optional
    Display the exposure and sources?  Default False.  (Requires
    display to have been passed to task constructor)
doDisplayIndices : `bool`, optional
    Display the source indices?  Default False.  (Requires display to
    have been passed to task constructor)
mode : {'auto', 'donut', 'spec', 'photo'}, optional
    Mode to run in.  Default 'auto'.
binSize : `int`, optional
    Binning factor for exposure.  Default is None, which let's subtasks
    control rebinning directly.
donutDiameter : `float`, optional
    Donut diameter in pixels.  Default is None, which will estimate the
    donut diameter from the exposure metadata.

Returns
-------
result : `pipeBase.Struct`
    Result of the peek.
    Struct containing:
        - mode : `str`
            Peek mode that was run.
        - binSize : `int`
            Binning factor used.
        - binnedSourceCat : `lsst.afw.table.SourceCatalog`
            Source catalog from the binned exposure.
        - table : `astropy.table.Table`
            Curated source table in unbinned coordinates.
        - brightestIdx : `int`
            Index of brightest source in source catalog.
        - brightestCentroid : `lsst.geom.Point2D`
            Brightest source centroid in unbinned pixel coords.
        - brightestPixelShape : `lsst.afw.geom.Quadrupole`
            Brightest source shape in unbinned pixel coords.
        - brightestEquatorialShape : `lsst.afw.geom.Quadrupole`
            Brightest source shape in equitorial coordinates (arcsec).
        - brightestAltAzShape : `lsst.afw.geom.Quadrupole`
            Brightest source shape in alt/az coordinates (arcsec).
        - psfPixelShape : `lsst.afw.geom.Quadrupole`
            Estimated PSF shape in unbinned pixel coords.
        - psfEquatorialShape : `lsst.afw.geom.Quadrupole`
            Estimated PSF shape in equitorial coordinates (arcsec).
        - psfAltAzShape : `lsst.afw.geom.Quadrupole`
            Estimated PSF shape in alt/az coordinates (arcsec).
        - pixelMedian : `float`
            Median estimate of entire image.
        - pixelMode : `float`
            Mode estimate of entire image.

Definition at line 817 of file peekExposure.py.

826 ) -> pipeBase.Struct:
827 """
828 Parameters
829 ----------
830 exposure : `lsst.afw.image.Exposure`
831 Exposure at which to peek.
832 doDisplay : `bool`, optional
833 Display the exposure and sources? Default False. (Requires
834 display to have been passed to task constructor)
835 doDisplayIndices : `bool`, optional
836 Display the source indices? Default False. (Requires display to
837 have been passed to task constructor)
838 mode : {'auto', 'donut', 'spec', 'photo'}, optional
839 Mode to run in. Default 'auto'.
840 binSize : `int`, optional
841 Binning factor for exposure. Default is None, which let's subtasks
842 control rebinning directly.
843 donutDiameter : `float`, optional
844 Donut diameter in pixels. Default is None, which will estimate the
845 donut diameter from the exposure metadata.
846
847 Returns
848 -------
849 result : `pipeBase.Struct`
850 Result of the peek.
851 Struct containing:
852 - mode : `str`
853 Peek mode that was run.
854 - binSize : `int`
855 Binning factor used.
856 - binnedSourceCat : `lsst.afw.table.SourceCatalog`
857 Source catalog from the binned exposure.
858 - table : `astropy.table.Table`
859 Curated source table in unbinned coordinates.
860 - brightestIdx : `int`
861 Index of brightest source in source catalog.
862 - brightestCentroid : `lsst.geom.Point2D`
863 Brightest source centroid in unbinned pixel coords.
864 - brightestPixelShape : `lsst.afw.geom.Quadrupole`
865 Brightest source shape in unbinned pixel coords.
866 - brightestEquatorialShape : `lsst.afw.geom.Quadrupole`
867 Brightest source shape in equitorial coordinates (arcsec).
868 - brightestAltAzShape : `lsst.afw.geom.Quadrupole`
869 Brightest source shape in alt/az coordinates (arcsec).
870 - psfPixelShape : `lsst.afw.geom.Quadrupole`
871 Estimated PSF shape in unbinned pixel coords.
872 - psfEquatorialShape : `lsst.afw.geom.Quadrupole`
873 Estimated PSF shape in equitorial coordinates (arcsec).
874 - psfAltAzShape : `lsst.afw.geom.Quadrupole`
875 Estimated PSF shape in alt/az coordinates (arcsec).
876 - pixelMedian : `float`
877 Median estimate of entire image.
878 - pixelMode : `float`
879 Mode estimate of entire image.
880 """
881 # Make a copy so the original image is unmodified.
882 exposure = exposure.clone()
883 try:
884 result = self._run(exposure, doDisplay, doDisplayIndices, mode, binSize, donutDiameter)
885 except Exception as e:
886 self.log.warning(f"Peek failed: {e}")
887 result = pipeBase.Struct(
888 mode="failed",
889 binSize=0,
890 binnedSourceCat=None,
891 table=None,
892 brightestIdx=0,
893 brightestCentroid=Point2D(np.nan, np.nan),
894 brightestPixelShape=Quadrupole(np.nan, np.nan, np.nan),
895 brightestEquatorialShape=Quadrupole(np.nan, np.nan, np.nan),
896 brightestAltAzShape=Quadrupole(np.nan, np.nan, np.nan),
897 psfPixelShape=Quadrupole(np.nan, np.nan, np.nan),
898 psfEquatorialShape=Quadrupole(np.nan, np.nan, np.nan),
899 psfAltAzShape=Quadrupole(np.nan, np.nan, np.nan),
900 pixelMedian=np.nan,
901 pixelMode=np.nan,
902 )
903 return result
904

◆ runPeek()

tuple[str, int, afwTable.SourceCatalog] lsst.pipe.tasks.peekExposure.PeekExposureTask.runPeek ( self,
afwImage.Exposure exposure,
str mode,
float donutDiameter,
int | None binSize = None )
Classify exposure and run appropriate PeekTask wrapper.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to peek.
mode : {'auto', 'donut', 'spec', 'photo'}
    Mode to run in.
donutDiameter : `float`
    Donut diameter in pixels.
binSize : `int`, optional
    Binning factor for exposure.  Default is None, which let's subtasks
    control rebinning directly.

Returns
-------
result : `pipeBase.Struct`
    Result of the peek.
    Struct containing:
        - mode : `str`
            Peek mode that was run.
        - binSize : `int`
            Binning factor used.
        - binnedSourceCat : `lsst.afw.table.SourceCatalog`
            Source catalog from the binned exposure.

Definition at line 965 of file peekExposure.py.

971 ) -> tuple[str, int, afwTable.SourceCatalog]:
972 """Classify exposure and run appropriate PeekTask wrapper.
973
974 Parameters
975 ----------
976 exposure : `lsst.afw.image.Exposure`
977 Exposure to peek.
978 mode : {'auto', 'donut', 'spec', 'photo'}
979 Mode to run in.
980 donutDiameter : `float`
981 Donut diameter in pixels.
982 binSize : `int`, optional
983 Binning factor for exposure. Default is None, which let's subtasks
984 control rebinning directly.
985
986 Returns
987 -------
988 result : `pipeBase.Struct`
989 Result of the peek.
990 Struct containing:
991 - mode : `str`
992 Peek mode that was run.
993 - binSize : `int`
994 Binning factor used.
995 - binnedSourceCat : `lsst.afw.table.SourceCatalog`
996 Source catalog from the binned exposure.
997 """
998 if mode == "auto":
999 # Note, no attempt to handle dispersed donuts. They'll default to
1000 # donut mode.
1001 if donutDiameter > self.config.donutThreshold:
1002 mode = "donut"
1003 else:
1004 if exposure.getInfo().getVisitInfo().instrumentLabel == "LATISS":
1005 # only LATISS images *can* be dispersed, and isDispersedExp
1006 # only works cleanly for LATISS
1007 mode = "spec" if isDispersedExp(exposure) else "photo"
1008 else:
1009 mode = "photo"
1010
1011 match mode:
1012 case "donut":
1013 result = self.donut.run(exposure, donutDiameter, binSize=binSize)
1014 binSizeOut = result.binSize
1015 case "spec":
1016 result = self.spec.run(exposure, binSize=binSize)
1017 binSizeOut = result.binSize
1018 if len(result.binnedSourceCat) == 0:
1019 self.log.warn("No sources found in spec mode.")
1020 if self.config.doPhotoFallback:
1021 self.log.warn("Falling back to photo mode.")
1022 # Note that spec.run already rebinned the image,
1023 # so we don't need to do it again.
1024 result = self.photo.run(exposure, binSize=1)
1025 case "photo":
1026 result = self.photo.run(exposure, binSize=binSize)
1027 binSizeOut = result.binSize
1028 case _:
1029 raise ValueError(f"Unknown mode {mode}")
1030 return result.mode, binSizeOut, result.binnedSourceCat
1031

◆ transformShapes()

tuple[list[afwGeom.Quadrupole], list[afwGeom.Quadrupole]] lsst.pipe.tasks.peekExposure.PeekExposureTask.transformShapes ( self,
afwGeom.Quadrupole shapes,
afwImage.Exposure exposure,
int binSize )
Transform shapes from x/y pixel coordinates to equitorial and
horizon coordinates.

Parameters
----------
shapes : `list` of `lsst.afw.geom.Quadrupole`
    List of shapes (in pixel coordinates) to transform.
exposure : `lsst.afw.image.Exposure`
    Exposure containing WCS and VisitInfo for transformation.
binSize : `int`
    Binning factor used.

Returns
-------
equatorialShapes : `list` of `lsst.afw.geom.Quadrupole`
    List of shapes transformed to equitorial (North and West)
    coordinates.  Units are arcseconds.
altAzShapes : `list` of `lsst.afw.geom.Quadrupole`
    List of shapes transformed to alt/az coordinates.  Units are
    arcseconds.

Definition at line 1174 of file peekExposure.py.

1176 ) -> tuple[list[afwGeom.Quadrupole], list[afwGeom.Quadrupole]]:
1177 """Transform shapes from x/y pixel coordinates to equitorial and
1178 horizon coordinates.
1179
1180 Parameters
1181 ----------
1182 shapes : `list` of `lsst.afw.geom.Quadrupole`
1183 List of shapes (in pixel coordinates) to transform.
1184 exposure : `lsst.afw.image.Exposure`
1185 Exposure containing WCS and VisitInfo for transformation.
1186 binSize : `int`
1187 Binning factor used.
1188
1189 Returns
1190 -------
1191 equatorialShapes : `list` of `lsst.afw.geom.Quadrupole`
1192 List of shapes transformed to equitorial (North and West)
1193 coordinates. Units are arcseconds.
1194 altAzShapes : `list` of `lsst.afw.geom.Quadrupole`
1195 List of shapes transformed to alt/az coordinates. Units are
1196 arcseconds.
1197 """
1198 pt = Point2D(np.array([*exposure.getBBox().getCenter()]) / binSize)
1199 wcs = exposure.wcs
1200 visitInfo = exposure.info.getVisitInfo()
1201 parAngle = visitInfo.boresightParAngle
1202
1203 equatorialShapes = []
1204 altAzShapes = []
1205 for shape in shapes:
1206 if wcs is None:
1207 equatorialShapes.append(Quadrupole(np.nan, np.nan, np.nan))
1208 altAzShapes.append(Quadrupole(np.nan, np.nan, np.nan))
1209 continue
1210 # The WCS transforms to N (dec) and E (ra), but we want N and W to
1211 # conform with weak-lensing conventions. So we flip the [0]
1212 # component of the transformation.
1213 neTransform = wcs.linearizePixelToSky(pt, arcseconds).getLinear()
1214 nwTransform = LinearTransform(np.array([[-1, 0], [0, 1]]) @ neTransform.getMatrix())
1215 equatorialShapes.append(shape.transform(nwTransform))
1216
1217 # To get from N/W to alt/az, we need to additionally rotate by the
1218 # parallactic angle.
1219 rot = LinearTransform.makeRotation(parAngle).getMatrix()
1220 aaTransform = LinearTransform(nwTransform.getMatrix() @ rot)
1221 altAzShapes.append(shape.transform(aaTransform))
1222
1223 return equatorialShapes, altAzShapes
1224

◆ transformTable()

astropy.table.Table lsst.pipe.tasks.peekExposure.PeekExposureTask.transformTable ( self,
int binSize,
afwTable.SourceCatalog binnedSourceCat )
Make an astropy table from the source catalog but with
transformations back to the original unbinned coordinates.

Since there's some ambiguity in the apFlux apertures when binning,
we'll only populate the table with the slots columns (slot_apFlux
doesn't indicate an aperture radius).  For simplicity, do the same for
centroids and shapes too.

And since we're only copying over the slots_* columns, we remove the
"slots_" part of the column names and lowercase the first remaining
letter.

Parameters
----------
binSize : `int`
    Binning factor used.
binnedSourceCat : `lsst.afw.table.SourceCatalog`
    Source catalog from the binned exposure.

Returns
-------
table : `astropy.table.Table`
    Curated source table in unbinned coordinates.

Definition at line 1032 of file peekExposure.py.

1032 def transformTable(self, binSize: int, binnedSourceCat: afwTable.SourceCatalog) -> astropy.table.Table:
1033 """Make an astropy table from the source catalog but with
1034 transformations back to the original unbinned coordinates.
1035
1036 Since there's some ambiguity in the apFlux apertures when binning,
1037 we'll only populate the table with the slots columns (slot_apFlux
1038 doesn't indicate an aperture radius). For simplicity, do the same for
1039 centroids and shapes too.
1040
1041 And since we're only copying over the slots_* columns, we remove the
1042 "slots_" part of the column names and lowercase the first remaining
1043 letter.
1044
1045 Parameters
1046 ----------
1047 binSize : `int`
1048 Binning factor used.
1049 binnedSourceCat : `lsst.afw.table.SourceCatalog`
1050 Source catalog from the binned exposure.
1051
1052 Returns
1053 -------
1054 table : `astropy.table.Table`
1055 Curated source table in unbinned coordinates.
1056 """
1057 table = binnedSourceCat.asAstropy()
1058 cols = [n for n in table.colnames if n.startswith("slot")]
1059 table = table[cols]
1060 if "slot_Centroid_x" in cols:
1061 table["slot_Centroid_x"] = binSize * table["slot_Centroid_x"] + (binSize - 1) / 2
1062 table["slot_Centroid_y"] = binSize * table["slot_Centroid_y"] + (binSize - 1) / 2
1063 if "slot_Shape_x" in cols:
1064 table["slot_Shape_x"] = binSize * table["slot_Shape_x"] + (binSize - 1) / 2
1065 table["slot_Shape_y"] = binSize * table["slot_Shape_y"] + (binSize - 1) / 2
1066 table["slot_Shape_xx"] *= binSize**2
1067 table["slot_Shape_xy"] *= binSize**2
1068 table["slot_Shape_yy"] *= binSize**2
1069 # area and npixels are just confusing when binning, so remove.
1070 if "slot_PsfFlux_area" in cols:
1071 del table["slot_PsfFlux_area"]
1072 if "slot_PsfFlux_npixels" in cols:
1073 del table["slot_PsfFlux_npixels"]
1074
1075 table.rename_columns(
1076 [n for n in table.colnames if n.startswith("slot_")],
1077 [n[5:6].lower() + n[6:] for n in table.colnames if n.startswith("slot_")],
1078 )
1079
1080 return table
1081

◆ updateDisplay()

None lsst.pipe.tasks.peekExposure.PeekExposureTask.updateDisplay ( self,
afwImage.Exposure exposure,
int binSize,
afwTable.SourceCatalog binnedSourceCat,
int maxFluxIdx,
bool doDisplayIndices )
Update the afwDisplay with the exposure and sources.

Parameters
----------
exposure : `lsst.afw.image.Exposure`
    Exposure to peek.
binSize : `int`
    Binning factor used.
binnedSourceCat : `lsst.afw.table.SourceCatalog`
    Source catalog from the binned exposure.
maxFluxIdx : `int`
    Index of the brightest source in the catalog.
doDisplayIndices : `bool`
    Display the source indices?

Definition at line 1225 of file peekExposure.py.

1232 ) -> None:
1233 """Update the afwDisplay with the exposure and sources.
1234
1235 Parameters
1236 ----------
1237 exposure : `lsst.afw.image.Exposure`
1238 Exposure to peek.
1239 binSize : `int`
1240 Binning factor used.
1241 binnedSourceCat : `lsst.afw.table.SourceCatalog`
1242 Source catalog from the binned exposure.
1243 maxFluxIdx : `int`
1244 Index of the brightest source in the catalog.
1245 doDisplayIndices : `bool`
1246 Display the source indices?
1247 """
1248 if self._display is None:
1249 raise RuntimeError("Display failed as no display provided during init()")
1250
1251 visitInfo = exposure.info.getVisitInfo()
1252 self._display.mtv(exposure)
1253 wcs = exposure.wcs
1254 if wcs is not None:
1255 plotRose(
1256 self._display,
1257 wcs,
1258 Point2D(200 / binSize, 200 / binSize),
1259 parAng=visitInfo.boresightParAngle,
1260 len=100 / binSize,
1261 )
1262
1263 for idx, source in enumerate(binnedSourceCat):
1264 x, y = source.getCentroid()
1265 sh = source.getShape()
1266 self._display.dot(sh, x, y)
1267 if doDisplayIndices:
1268 self._display.dot(str(idx), x, y)
1269
1270 if maxFluxIdx != IDX_SENTINEL:
1271 self._display.dot(
1272 "+",
1273 *binnedSourceCat[maxFluxIdx].getCentroid(),
1274 ctype=afwDisplay.RED,
1275 size=10,
1276 )

Member Data Documentation

◆ _DefaultName

str lsst.pipe.tasks.peekExposure.PeekExposureTask._DefaultName = "peekExposureTask"
staticprotected

Definition at line 775 of file peekExposure.py.

◆ _display

lsst.pipe.tasks.peekExposure.PeekExposureTask._display
protected

Definition at line 784 of file peekExposure.py.

◆ config

PeekExposureTaskConfig lsst.pipe.tasks.peekExposure.PeekExposureTask.config
static

Definition at line 771 of file peekExposure.py.

◆ ConfigClass

lsst.pipe.tasks.peekExposure.PeekExposureTask.ConfigClass = PeekExposureTaskConfig
static

Definition at line 770 of file peekExposure.py.

◆ donut

PeekDonutTask lsst.pipe.tasks.peekExposure.PeekExposureTask.donut
static

Definition at line 772 of file peekExposure.py.

◆ photo

PeekPhotoTask lsst.pipe.tasks.peekExposure.PeekExposureTask.photo
static

Definition at line 773 of file peekExposure.py.

◆ spec

PeekSpecTask lsst.pipe.tasks.peekExposure.PeekExposureTask.spec
static

Definition at line 774 of file peekExposure.py.


The documentation for this class was generated from the following file: