Exemple #1
0
def addAmp(ampCatalog, i, eparams):
    """ Add an amplifier to an AmpInfoCatalog

    @param ampCatalog: An instance of an AmpInfoCatalog object to fill with amp properties
    @param i which amplifier? (i == 0 ? left : right)
    @param eparams: Electronic parameters.  This is a list of tuples with (i, params),
                    where params is a dictionary of electronic parameters.
    """
    #
    # Layout of active and overclock pixels in the as-readout data  The layout is:
    #     Amp0 || extended | overclock | data || data | overclock | extended || Amp1
    # for each row; all rows are identical in drift-scan data
    #
    height = 1361  # number of rows in a frame
    width = 1024  # number of data pixels read out through one amplifier
    nExtended = 8  # number of pixels in the extended register
    nOverclock = 32  # number of (horizontal) overclock pixels
    #
    # Construct the needed bounding boxes given that geometrical information.
    #
    # Note that all the offsets are relative to the origin of this amp, not to its eventual
    # position in the CCD
    #
    record = ampCatalog.addNew()
    xtot = width + nExtended + nOverclock
    allPixels = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(xtot, height))
    biasSec = geom.BoxI(geom.PointI(nExtended if i == 0 else width, 0),
                        geom.ExtentI(nOverclock, height))
    dataSec = geom.BoxI(
        geom.PointI(nExtended + nOverclock if i == 0 else 0, 0),
        geom.ExtentI(width, height))
    emptyBox = geom.BoxI()
    bbox = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(width, height))
    bbox.shift(geom.Extent2I(width * i, 0))

    shiftp = geom.Extent2I(xtot * i, 0)
    allPixels.shift(shiftp)
    biasSec.shift(shiftp)
    dataSec.shift(shiftp)

    record.setBBox(bbox)
    record.setRawXYOffset(geom.ExtentI(0, 0))
    record.setName('left' if i == 0 else 'right')
    record.setReadoutCorner(afwTable.LL if i == 0 else afwTable.LR)
    record.setGain(eparams['gain'])
    record.setReadNoise(eparams['readNoise'])
    record.setSaturation(eparams['fullWell'])
    record.setSuspectLevel(float("nan"))
    record.setLinearityType(NullLinearityType)
    record.setLinearityCoeffs([
        1.,
    ])
    record.setHasRawInfo(True)
    record.setRawFlipX(False)
    record.setRawFlipY(False)
    record.setRawBBox(allPixels)
    record.setRawDataBBox(dataSec)
    record.setRawHorizontalOverscanBBox(biasSec)
    record.setRawVerticalOverscanBBox(emptyBox)
    record.setRawPrescanBBox(emptyBox)
Exemple #2
0
 def testValid(self):
     test_data = {
         "[1:1084,1:1024]":
         geom.BoxI(geom.PointI(0, 0), geom.PointI(1083, 1023)),
         "[0:0,0:0]":
         geom.BoxI(geom.PointI(-1, -1), geom.PointI(-1, -1))
     }
     for val, result in test_data.items():
         self.assertEqual(obsBase.bboxFromIraf(val), result)
Exemple #3
0
def bboxFromIraf(irafBBoxStr):
    """Return a Box2I corresponding to an IRAF-style BBOX

    [x0:x1,y0:y1] where x0 and x1 are the one-indexed start and end columns, and correspondingly
    y0 and y1 are the start and end rows.
    """

    mat = re.search(r"^\[([-\d]+):([-\d]+),([-\d]+):([-\d]+)\]$", irafBBoxStr)
    if not mat:
        raise RuntimeError("Unable to parse IRAF-style bbox \"%s\"" %
                           irafBBoxStr)
    x0, x1, y0, y1 = [int(_) for _ in mat.groups()]

    return geom.BoxI(geom.PointI(x0 - 1, y0 - 1), geom.PointI(x1 - 1, y1 - 1))
    def testParentTrailingSlash2527(self):
        """Just like testParentNormal, but put a trailing slash on the root
        paths.

        Test that an object can be found at root location and put into an
        output location. Then test that when the output locaiton is used as
        an input location, and with a new output location, that the object is
        found in the first output location."""
        # todo these shouldn't be commented out, I think the test wants the
        # trailing slash.
        testOutput = self.mkdtemp("testOutput") + '/'
        butler = dafPersist.Butler(inputs={
            'root': ROOT + '/',
            'mapper': MinMapper1
        },
                                   outputs=testOutput)
        mapper1 = butler._repos.inputs()[0].repo._mapper
        loc = mapper1.map("x", dict(sensor="1,1"), write=True)
        self.assertEqual(loc.getPythonType(), "lsst.afw.geom.BoxI")
        self.assertEqual(loc.getCppType(), "BoxI")
        self.assertEqual(loc.getStorageName(), "PickleStorage")
        self.assertEqual(loc.getLocations(), ["foo-1,1.pickle"])
        self.assertEqual(loc.getStorage().root, ROOT)
        self.assertEqual(loc.getAdditionalData().toString(),
                         "sensor = \"1,1\"\n")
        box = geom.BoxI(geom.PointI(0, 1), geom.PointI(2, 3))
        butler.put(box, "x", sensor="1,1")
        self.assertTrue(
            os.path.exists(os.path.join(testOutput,
                                        loc.getLocations()[0])))
        del butler
        del mapper1

        testOutput2 = self.mkdtemp("testOutput2") + '/'
        butler = dafPersist.Butler(inputs={
            'root': testOutput,
            'mapper': MinMapper1
        },
                                   outputs=testOutput2)
        mapper2 = butler._repos.inputs()[0].repo._mapper
        loc = mapper2.map("x", dict(sensor="1,1"))
        self.assertEqual(loc.getPythonType(), "lsst.afw.geom.BoxI")
        self.assertEqual(loc.getCppType(), "BoxI")
        self.assertEqual(loc.getStorageName(), "PickleStorage")
        self.assertEqual(loc.getLocations(), ["foo-1,1.pickle"])
        self.assertEqual(os.path.normpath(loc.getStorage().root),
                         os.path.normpath(testOutput))
        self.assertEqual(loc.getAdditionalData().toString(),
                         "sensor = \"1,1\"\n")
Exemple #5
0
    def subtractStars(self, exposure, catalog, chi_lim=-1):
        """Subtract the exposure's PSF from all the sources in catalog"""
        mi, psf = exposure.getMaskedImage(), exposure.getPsf()

        subtracted = mi.Factory(mi, True)
        for s in catalog:
            xc, yc = s.getX(), s.getY()
            bbox = subtracted.getBBox(afwImage.PARENT)
            if bbox.contains(geom.PointI(int(xc), int(yc))):
                try:
                    measAlg.subtractPsf(psf, subtracted, xc, yc)
                except Exception:
                    pass
        chi = subtracted.Factory(subtracted, True)
        var = subtracted.getVariance()
        np.sqrt(var.getArray(), var.getArray())  # inplace sqrt
        chi /= var

        if display:
            afwDisplay.Display(frame=1).mtv(subtracted, title="Subtracted")
            afwDisplay.Display(frame=2).mtv(chi, title="Chi")
            xc, yc = exposure.getWidth() // 2, exposure.getHeight() // 2
            afwDisplay.Display(frame=3).mtv(psf.computeImage(
                geom.Point2D(xc, yc)),
                                            title="Psf %.1f,%.1f" % (xc, yc))

        chi_min, chi_max = np.min(chi.getImage().getArray()), np.max(
            chi.getImage().getArray())
        if False:
            print(chi_min, chi_max)

        if chi_lim > 0:
            self.assertGreater(chi_min, -chi_lim)
            self.assertLess(chi_max, chi_lim)
Exemple #6
0
def display_cutout(exposure, x, y, title=None, frame=None, cutout_size=100):
    cutout_exp = make_cutout(exposure, x, y, cutout_size=cutout_size)
    xy = geom.PointI(x, y)
    afwDisplay.setDefaultBackend('matplotlib')
    display = afwDisplay.Display(frame=frame)
    display.mtv(cutout_exp)
    plt.title(title)
Exemple #7
0
    def testSwap(self):
        x00, y00, x01, y01 = (0, 1, 2, 3)
        x10, y10, x11, y11 = (4, 5, 6, 7)

        box0 = geom.Box2I(geom.PointI(x00, y00), geom.PointI(x01, y01))
        box1 = geom.Box2I(geom.PointI(x10, y10), geom.PointI(x11, y11))
        box0.swap(box1)

        self.assertEqual(box0.getMinX(), x10)
        self.assertEqual(box0.getMinY(), y10)
        self.assertEqual(box0.getMaxX(), x11)
        self.assertEqual(box0.getMaxY(), y11)

        self.assertEqual(box1.getMinX(), x00)
        self.assertEqual(box1.getMinY(), y00)
        self.assertEqual(box1.getMaxX(), x01)
        self.assertEqual(box1.getMaxY(), y01)
    def run(self, durationInSeconds=-1):
        """Run the monitor, displaying new images as they are taken.

        Parameters
        ----------
        durationInSeconds : `int`, optional
            How long to run for. Use -1 for infinite.
        """

        if durationInSeconds == -1:
            nLoops = int(1e9)
        else:
            nLoops = int(durationInSeconds // self.cadence)

        lastDisplayed = -1
        for i in range(nLoops):
            try:
                dataId, expId = self._getLatestImageDataIdAndExpId()

                if lastDisplayed == expId:
                    sleep(self.cadence)
                    continue

                if self.runIsr:
                    exp = self.bestEffort.getExposure(dataId)
                else:
                    exp = self.butler.get('raw', dataId=dataId)

                # TODO: add logic to deal with amp overlay and chip center
                # being mutually exclusive
                if self.measureFromChipCenter:  # after writing only!
                    exp.setXY0(geom.PointI(-2036, -2000))

                print(f"Displaying {dataId}...")
                imageInfoText = self._makeImageInfoText(dataId,
                                                        exp,
                                                        asList=True)
                # too long of a title breaks Java FITS i/o
                fireflyTitle = " ".join([s for s in imageInfoText])[:67]
                try:
                    self.display.scale('asinh', 'zscale')
                    self.display.mtv(exp, title=fireflyTitle)
                except Exception as e:  # includes JSONDecodeError, HTTPError, anything else
                    print(f'Caught error {e}, skipping this image'
                          )  # TODO: try again maybe?

                if self.overlayAmps:
                    cgUtils.overlayCcdBoxes(exp.getDetector(),
                                            display=self.display,
                                            isTrimmed=True)

                self._printImageInfo(imageInfoText)
                lastDisplayed = expId

            except NotFoundError as e:  # NotFoundError when filters aren't defined
                print(f'Skipped displaying {dataId} due to {e}')
        return
Exemple #9
0
def addDefects(exp, nBadCols=10):
    img = exp.getMaskedImage().getImage()
    (xsize, ysize) = img.getDimensions()
    defectList = measAlg.Defects()

    # set some bad cols and add them to a defect list
    for xi in numpy.random.randint(0, xsize, nBadCols):
        yi = numpy.random.randint(0, ysize)
        xi, yi = int(xi), int(yi)
        bbox = geom.Box2I(geom.PointI(xi, 0), geom.ExtentI(1, yi+1))
        subIm = afwImage.ImageF(img, bbox)
        subIm.set(1e7)
        defectList.append(bbox)
    # set a 15 pixel box of defects at the upper left corner to demonstrate fallbackValue
    bbox = geom.Box2I(geom.PointI(0, ysize-15), geom.ExtentI(15, 15))
    subIm = afwImage.ImageF(img, bbox)
    subIm.set(1e7)
    defectList.append(bbox)
    return defectList
Exemple #10
0
    def testParentNormal(self):
        """Test that an object can be found at root location and put into an
        output location. Then test that when the output locaiton is used as an
        input location, and with a new output location, that the object is
        found in the first output location.
        """
        testOutput = self.mkdtemp("testOutput")
        butler = dafPersist.Butler(inputs={
            'root': ROOT,
            'mapper': MinMapper1
        },
                                   outputs=testOutput)
        mapper1 = butler._repos.inputs()[0].repo._mapper
        loc = mapper1.map("x", dict(sensor="1,1"), write=True)
        self.assertEqual(loc.getPythonType(), "lsst.afw.geom.BoxI")
        self.assertEqual(loc.getCppType(), "BoxI")
        self.assertEqual(loc.getStorageName(), "PickleStorage")
        self.assertEqual(loc.getLocations(), ["foo-1,1.pickle"])
        self.assertEqual(loc.getAdditionalData().toString(),
                         "sensor = \"1,1\"\n")
        box = geom.BoxI(geom.PointI(0, 1), geom.PointI(2, 3))
        butler.put(box, "x", sensor="1,1")
        self.assertTrue(
            os.path.exists(os.path.join(testOutput,
                                        loc.getLocations()[0])))
        del butler

        testOutput2 = self.mkdtemp("testOutput2")
        butler = dafPersist.Butler(inputs={
            'root': testOutput,
            'mapper': MinMapper1
        },
                                   outputs=testOutput2)
        mapper2 = butler._repos.inputs()[0].repo._mapper
        loc = mapper2.map("x", dict(sensor="1,1"))
        self.assertEqual(loc.getPythonType(), "lsst.afw.geom.BoxI")
        self.assertEqual(loc.getCppType(), "BoxI")
        self.assertEqual(loc.getStorageName(), "PickleStorage")
        self.assertEqual(loc.getLocations(), ["foo-1,1.pickle"])
        self.assertEqual(loc.getStorage().root, testOutput)
        self.assertEqual(loc.getAdditionalData().toString(),
                         "sensor = \"1,1\"\n")
Exemple #11
0
def show_injection(exposure,
                   x,
                   y,
                   x_ref=False,
                   y_ref=False,
                   title=None,
                   frame=None,
                   cutout_size=100):
    # x, y:            center of the postage stamps, shown in red
    # x_ref, y_ref:    a reference circle shown in green, it can be used to compared

    xy = geom.PointI(x, y)
    afwDisplay.setDefaultBackend('matplotlib')
    display = afwDisplay.Display(frame=frame)
    display.mtv(exposure)
    display.dot('o', xy.getX(), xy.getY(), ctype='red')
    if x_ref or y_ref:
        xy_ref = geom.PointI(x_ref, y_ref)
        display.dot('o', xy_ref.getX(), xy_ref.getY(), ctype='green')
    plt.title(title)
Exemple #12
0
def findBrightestStarRHL(exp, minArea=100, maxRadialOffset=1500):
    import lsst.afw.detection as afwDetect
    import lsst.afw.image as afwImage
    import lsst.afw.math as afwMath

    cexp = exp.clone()

    sigma = 4

    ksize = 1 + 4*int(sigma + 1)
    gauss1d = afwMath.GaussianFunction1D(sigma)
    kernel = afwMath.SeparableKernel(ksize, ksize, gauss1d, gauss1d)

    convolvedImage = cexp.maskedImage.Factory(cexp.maskedImage.getBBox())
    afwMath.convolve(convolvedImage, cexp.maskedImage, kernel)
    bbox = geom.BoxI(geom.PointI(ksize//2, ksize//2), geom.PointI(cexp.getWidth() - ksize//2 - 1, cexp.getHeight() - ksize//2 - 1))
    tmp = cexp.maskedImage[bbox]
    cexp.image *= 0
    tmp[bbox, afwImage.PARENT] = convolvedImage[bbox]

    del convolvedImage; del tmp

    if False:
        defectBBoxes = [
            geom.BoxI(geom.PointI(548, 3562), geom.PointI(642, 3999)),
            geom.BoxI(geom.PointI(474, 3959), geom.PointI(1056, 3999)),
            geom.BoxI(geom.PointI(500, 0),    geom.PointI(680, 40)),
        ]
        for bbox in defectBBoxes:
            cexp.maskedImage[bbox] = 0

    threshold = 1000
    feet = afwDetect.FootprintSet(cexp.maskedImage, afwDetect.Threshold(threshold), "DETECTED").getFootprints()

    maxVal = None
    centroid = None
    for foot in feet:
        peak = foot.peaks[0]
        
        if minArea > 0 and foot.getArea() < minArea:
            continue
            
        x, y = peak.getCentroid()
        if np.hypot(x - 2036, y - 2000) > maxRadialOffset:
            continue

        if maxVal is None or peak.getPeakValue() > maxVal:
            maxVal = peak.getPeakValue()
            centroid = peak.getCentroid()
            
    return centroid
Exemple #13
0
def radec2xy(ra, dec, wcs):
    """This function converts radec to xy.
       ra:        ra in degree
       dec:       dec in degree
       wcs:       wcs of an exposure
       
       Returns:
       xy coordinates
    """
    radec = geom.SpherePoint(ra * geom.degrees, dec * geom.degrees)
    xy = geom.PointI(wcs.skyToPixel(radec))
    return xy.getX(), xy.getY()
Exemple #14
0
    def _gridImage(self, maskedImage, binsize, statsFlag):
        """Private method to grid an image for debugging"""
        width, height = maskedImage.getDimensions()
        x0, y0 = maskedImage.getXY0()
        xedges = numpy.arange(0, width, binsize)
        yedges = numpy.arange(0, height, binsize)
        xedges = numpy.hstack((xedges, width))  # add final edge
        yedges = numpy.hstack((yedges, height))  # add final edge

        # Use lists/append to protect against the case where
        # a bin has no valid pixels and should not be included in the fit
        bgX = []
        bgY = []
        bgZ = []
        bgdZ = []

        for ymin, ymax in zip(yedges[0:-1], yedges[1:]):
            for xmin, xmax in zip(xedges[0:-1], xedges[1:]):
                subBBox = geom.Box2I(
                    geom.PointI(int(x0 + xmin), int(y0 + ymin)),
                    geom.PointI(int(x0 + xmax - 1), int(y0 + ymax - 1)))
                subIm = afwImage.MaskedImageF(maskedImage, subBBox,
                                              afwImage.PARENT, False)
                stats = afwMath.makeStatistics(
                    subIm, afwMath.MEAN | afwMath.MEANCLIP | afwMath.MEDIAN
                    | afwMath.NPOINT | afwMath.STDEV, self.sctrl)
                npoints, _ = stats.getResult(afwMath.NPOINT)
                if npoints >= 2:
                    stdev, _ = stats.getResult(afwMath.STDEV)
                    if stdev < self.config.gridStdevEpsilon:
                        stdev = self.config.gridStdevEpsilon
                    bgX.append(0.5 * (x0 + xmin + x0 + xmax))
                    bgY.append(0.5 * (y0 + ymin + y0 + ymax))
                    bgdZ.append(stdev / numpy.sqrt(npoints))
                    est, _ = stats.getResult(statsFlag)
                    bgZ.append(est)

        return numpy.array(bgX), numpy.array(bgY), numpy.array(
            bgZ), numpy.array(bgdZ)
Exemple #15
0
def ccdPixelToAmpPixel(xy, detector):
    r"""Given an position within a detector return position within an amplifier

    Parameters
    ----------
    xy : `lsst.geom.PointD`
       pixel position within detector
    detector : `lsst.afw.cameraGeom.Detector`
        The requested detector

    N.b. all pixel coordinates have the centre of the bottom-left pixel
    at (0.0, 0.0)

    Returns
    -------
    amp : `lsst.afw.table.AmpInfoRecord`
       The amplifier that the pixel lies in
    ampXY : `lsst.geom.PointI`
       The pixel coordinate relative to the corner of the single-amp image

    Raises
    ------
    RuntimeError
        If the requested pixel doesn't lie on the detector
    """

    found = False
    for amp in detector:
        if geom.BoxD(amp.getBBox()).contains(xy):
            found = True
            xy = geom.PointI(xy)     # pixel coordinates as ints
            break

    if not found:
        raise RuntimeError("Point (%g, %g) does not lie on detector %s" % (xy[0], xy[1], detector.getName()))

    x, y = xy - amp.getBBox().getBegin()   # offset from origin of amp's data segment

    # Allow for flips (due e.g. to physical location of the amplifiers)
    w, h = amp.getRawDataBBox().getDimensions()
    if amp.getRawFlipX():
        x = w - x - 1

    if amp.getRawFlipY():
        y = h - y - 1

    dxy = amp.getRawBBox().getBegin() - amp.getRawDataBBox().getBegin()   # correction for overscan etc.
    xy = geom.ExtentI(x, y) - dxy

    return amp, xy
Exemple #16
0
def display_exposure(exposure,
                     x,
                     y,
                     cutout_size=60,
                     coord_list=None,
                     scale=None,
                     frame=None,
                     show_colorbar=False,
                     title=None,
                     save_name=None):
    """This function displays the postage stamp of an exposure. The center of the postage stamp
       is marked by a red circle. We can also overlay blue circles corresponding to the coordinaes
       given in the coord_list on the postage stamp.
       exposure:       lsst.afw.image.exposure.exposure.ExposureF
       x:              x pixel coordinate
       y:              y pixel coordinate
       cutout_size:    Width(in pixel unit) of the postage stamp , default value is 60
       coord_list:     A list of coordinates where we can overlay blue circles on the postage stamp
       scale:          [min_val, max_val], set the min value and the max value for display,
                       default is None
       frame:          The frame of the afwDisplay.Display object
       show_colorbar:  Show colorbar of the postage stamp, default is False
       title:          Title of the postage stamp
       save_name:      If provided, the postage stamp will be saved as 'save_name.png' in the current
                       working directory, default if None
    """
    cutout_extent = geom.ExtentI(cutout_size, cutout_size)
    radec = geom.SpherePoint(exposure.getWcs().pixelToSky(x, y))
    cutout_image = exposure.getCutout(radec, cutout_extent)

    xy = geom.PointI(x, y)
    display = afwDisplay.Display(frame=frame, backend='matplotlib')
    if scale:
        display.scale("linear", scale[0], scale[1])
    else:
        display.scale("linear", "zscale")
    display.mtv(cutout_image)
    if show_colorbar:
        display.show_colorbar()
    display.dot('o', xy.getX(), xy.getY(), ctype='red')

    if coord_list:
        for coord in coord_list:
            coord_x, coord_y = coord
            display.dot('o', coord_x, coord_y, ctype='blue')

    plt.title(title)
    if save_name:
        plt.savefig(save_name, dpi=500)
Exemple #17
0
        def format_coord(x, y, wcs=self._wcs, x0=self._xy0[0], y0=self._xy0[1],
                         origin=afwImage.PARENT, bbox=self._image.getBBox(afwImage.PARENT),
                         _useSexagesimal=self._useSexagesimal):

            fmt = '(%1.2f, %1.2f)'
            if self._mtvOrigin == afwImage.PARENT:
                msg = fmt % (x, y)
            else:
                msg = (fmt + "L") % (x - x0, y - y0)

            col = int(x + 0.5)
            row = int(y + 0.5)
            if bbox.contains(geom.PointI(col, row)):
                if wcs is not None:
                    raDec = wcs.pixelToSky(x, y)
                    ra = raDec[0].asDegrees()
                    dec = raDec[1].asDegrees()

                    if _useSexagesimal[0]:
                        from astropy import units as u
                        from astropy.coordinates import Angle as apAngle

                        kwargs = dict(sep=':', pad=True, precision=2)
                        ra = apAngle(ra*u.deg).to_string(unit=u.hour, **kwargs)
                        dec = apAngle(dec*u.deg).to_string(unit=u.deg, **kwargs)
                    else:
                        ra = "%9.4f" % ra
                        dec = "%9.4f" % dec

                    msg += r" (%s, %s): (%s, %s)" % (self.__alpha, self.__delta, ra, dec)

                msg += ' %1.3f' % (self._image[col, row])
                if self._mask:
                    val = self._mask[col, row]
                    if self._interpretMaskBits:
                        msg += " [%s]" % self._mask.interpret(val)
                    else:
                        msg += " 0x%x" % val

            return msg
Exemple #18
0
    def subtractStars(self, exposure, catalog, chi_lim=-1):
        """Subtract the exposure's PSF from all the sources in catalog"""
        mi, psf = exposure.getMaskedImage(), exposure.getPsf()

        subtracted = mi.Factory(mi, True)
        for s in catalog:
            xc, yc = s.getX(), s.getY()
            bbox = subtracted.getBBox(afwImage.PARENT)
            if bbox.contains(geom.PointI(int(xc), int(yc))):
                measAlg.subtractPsf(psf, subtracted, xc, yc)
        chi = subtracted.Factory(subtracted, True)
        var = subtracted.getVariance()
        np.sqrt(var.getArray(), var.getArray())  # inplace sqrt
        chi /= var

        chi_min = np.min(chi.getImage().getArray())
        chi_max = np.max(chi.getImage().getArray())
        print(chi_min, chi_max)

        if chi_lim > 0:
            self.assertGreater(chi_min, -chi_lim)
            self.assertLess(chi_max, chi_lim)
Exemple #19
0
 def _serial_box(self, start, end):
     llc = lsstGeom.PointI(start, self.imaging.getMinY())
     urc = lsstGeom.PointI(end, self.imaging.getMaxY())
     return lsstGeom.BoxI(llc, urc)
Exemple #20
0
def subtractXTalk(mi, coeffs, minPixelToMask=45000, crosstalkStr="CROSSTALK"):
    """Subtract the crosstalk from MaskedImage mi given a set of coefficients

    The pixels affected by signal over minPixelToMask have the crosstalkStr
    bit set
    """
    sctrl = afwMath.StatisticsControl()
    sctrl.setAndMask(mi.getMask().getPlaneBitMask("BAD"))
    bkgd = afwMath.makeStatistics(mi, afwMath.MEDIAN, sctrl).getValue()
    #
    # These are the pixels that are bright enough to cause crosstalk (more
    # precisely, the ones that we label as causing crosstalk; in reality all
    # pixels cause crosstalk)
    #
    tempStr = "TEMP"                    # mask plane used to record the bright pixels that we need to mask
    msk = mi.getMask()
    msk.addMaskPlane(tempStr)
    try:
        fs = afwDetect.FootprintSet(mi, afwDetect.Threshold(minPixelToMask), tempStr)

        mi.getMask().addMaskPlane(crosstalkStr)
        afwDisplay.getDisplay().setMaskPlaneColor(crosstalkStr, afwDisplay.MAGENTA)
        # the crosstalkStr bit will now be set whenever we subtract crosstalk
        fs.setMask(mi.getMask(), crosstalkStr)
        crosstalk = mi.getMask().getPlaneBitMask(crosstalkStr)

        width, height = mi.getDimensions()
        for i in range(nAmp):
            bbox = geom.BoxI(geom.PointI(i*(width//nAmp), 0), geom.ExtentI(width//nAmp, height))
            ampI = mi.Factory(mi, bbox)
            for j in range(nAmp):
                if i == j:
                    continue

                bbox = geom.BoxI(geom.PointI(j*(width//nAmp), 0), geom.ExtentI(width//nAmp, height))
                if (i + j)%2 == 1:
                    ampJ = afwMath.flipImage(mi.Factory(mi, bbox), True, False)  # no need for a deep copy
                else:
                    ampJ = mi.Factory(mi, bbox, afwImage.LOCAL, True)

                msk = ampJ.getMask()
                if np.all(msk.getArray() & msk.getPlaneBitMask("BAD")):
                    # Bad amplifier; ignore it completely --- its effect will
                    # come out in the bias
                    continue
                msk &= crosstalk

                ampJ -= bkgd
                ampJ *= coeffs[j][i]

                ampI -= ampJ
        #
        # Clear the crosstalkStr bit in the original bright pixels, where
        # tempStr is set
        #
        msk = mi.getMask()
        temp = msk.getPlaneBitMask(tempStr)
        xtalk_temp = crosstalk | temp
        np_msk = msk.getArray()
        mask_indicies = np.where(np.bitwise_and(np_msk, xtalk_temp) == xtalk_temp)
        np_msk[mask_indicies] &= getattr(np, np_msk.dtype.name)(~crosstalk)

    finally:
        msk.removeAndClearMaskPlane(tempStr, True)  # added in afw #1853
def makeBBoxFromList(ylist):
    """Given a list [(x0, y0), (xsize, ysize)], probably from a yaml file,
    return a BoxI
    """
    (x0, y0), (xsize, ysize) = ylist
    return geom.BoxI(geom.PointI(x0, y0), geom.ExtentI(xsize, ysize))
Exemple #22
0
    def _fillVisitCatalog(self,
                          visitCat,
                          groupedDataRefs,
                          visitCatDataRef=None):
        """
        Fill the visit catalog with visit metadata

        Parameters
        ----------
        visitCat: `afw.table.BaseCatalog`
           Catalog with schema from _makeFgcmVisitSchema()
        groupedDataRefs: `dict`
           Dictionary with visit keys, and `list`s of
           `lsst.daf.persistence.ButlerDataRef
        visitCatDataRef: `lsst.daf.persistence.ButlerDataRef`, optional
           Dataref to write visitCat for checkpoints
        """

        bbox = geom.BoxI(geom.PointI(0, 0), geom.PointI(1, 1))

        for i, visit in enumerate(sorted(groupedDataRefs)):
            # We don't use the bypasses since we need the psf info which does
            # not have a bypass
            # TODO: When DM-15500 is implemented in the Gen3 Butler, this
            # can be fixed

            # Do not read those that have already been read
            if visitCat['used'][i]:
                continue

            if (i % self.config.nVisitsPerCheckpoint) == 0:
                self.log.info("Retrieving metadata for %s %d (%d/%d)" %
                              (self.config.visitDataRefName, visit, i,
                               len(groupedDataRefs)))
                # Save checkpoint if desired
                if visitCatDataRef is not None:
                    visitCatDataRef.put(visitCat)

            # Note that the reference ccd is first in the list (if available).

            # The first dataRef in the group will be the reference ccd (if available)
            dataRef = groupedDataRefs[visit][0]

            exp = dataRef.get(datasetType='calexp_sub',
                              bbox=bbox,
                              flags=afwTable.SOURCE_IO_NO_FOOTPRINTS)

            visitInfo = exp.getInfo().getVisitInfo()
            f = exp.getFilter()
            psf = exp.getPsf()

            rec = visitCat[i]
            rec['visit'] = visit
            rec['filtername'] = f.getName()
            # TODO DM-26991: when gen2 is removed, gen3 workflow will make it
            # much easier to get the wcs's necessary to recompute the pointing
            # ra/dec at the center of the camera.
            radec = visitInfo.getBoresightRaDec()
            rec['telra'] = radec.getRa().asDegrees()
            rec['teldec'] = radec.getDec().asDegrees()
            rec['telha'] = visitInfo.getBoresightHourAngle().asDegrees()
            rec['telrot'] = visitInfo.getBoresightRotAngle().asDegrees()
            rec['mjd'] = visitInfo.getDate().get(system=DateTime.MJD)
            rec['exptime'] = visitInfo.getExposureTime()
            # convert from Pa to millibar
            # Note that I don't know if this unit will need to be per-camera config
            rec['pmb'] = visitInfo.getWeather().getAirPressure() / 100
            # Flag to signify if this is a "deep" field.  Not currently used
            rec['deepFlag'] = 0
            # Relative flat scaling (1.0 means no relative scaling)
            rec['scaling'][:] = 1.0
            # Median delta aperture, to be measured from stars
            rec['deltaAper'] = 0.0

            rec['psfSigma'] = psf.computeShape().getDeterminantRadius()

            if dataRef.datasetExists(datasetType='calexpBackground'):
                # Get background for reference CCD
                # This approximation is good enough for now
                bgStats = (bg[0].getStatsImage().getImage().array
                           for bg in dataRef.get(
                               datasetType='calexpBackground'))
                rec['skyBackground'] = sum(
                    np.median(bg[np.isfinite(bg)]) for bg in bgStats)
            else:
                self.log.warn(
                    'Sky background not found for visit %d / ccd %d' %
                    (visit, dataRef.dataId[self.config.ccdDataRefName]))
                rec['skyBackground'] = -1.0

            rec['used'] = 1
Exemple #23
0
 def bbox(self):
     """Return the detector bounding box from the separate box endpoint
     values.
     """
     return geom.BoxI(geom.PointI(self.bbox_x0, self.bbox_y0),
                      geom.PointI(self.bbox_x1, self.bbox_y1))
Exemple #24
0
    def setUp(self):
        config = SingleFrameMeasurementTask.ConfigClass()
        config.slots.apFlux = 'base_CircularApertureFlux_12_0'
        self.schema = afwTable.SourceTable.makeMinimalSchema()

        self.measureSources = SingleFrameMeasurementTask(self.schema,
                                                         config=config)

        width, height = 110, 301

        self.mi = afwImage.MaskedImageF(geom.ExtentI(width, height))
        self.mi.set(0)
        sd = 3  # standard deviation of image
        self.mi.getVariance().set(sd * sd)
        self.mi.getMask().addMaskPlane("DETECTED")

        self.ksize = 31  # size of desired kernel

        sigma1 = 1.75
        sigma2 = 2 * sigma1

        self.exposure = afwImage.makeExposure(self.mi)
        self.exposure.setPsf(
            measAlg.DoubleGaussianPsf(self.ksize, self.ksize, 1.5 * sigma1, 1,
                                      0.1))
        cdMatrix = np.array([1.0, 0.0, 0.0, 1.0])
        cdMatrix.shape = (2, 2)
        wcs = afwGeom.makeSkyWcs(crpix=geom.PointD(0, 0),
                                 crval=geom.SpherePoint(
                                     0.0, 0.0, geom.degrees),
                                 cdMatrix=cdMatrix)
        self.exposure.setWcs(wcs)

        #
        # Make a kernel with the exactly correct basis functions.
        # Useful for debugging
        #
        basisKernelList = []
        for sigma in (sigma1, sigma2):
            basisKernel = afwMath.AnalyticKernel(
                self.ksize, self.ksize,
                afwMath.GaussianFunction2D(sigma, sigma))
            basisImage = afwImage.ImageD(basisKernel.getDimensions())
            basisKernel.computeImage(basisImage, True)
            basisImage /= np.sum(basisImage.getArray())

            if sigma == sigma1:
                basisImage0 = basisImage
            else:
                basisImage -= basisImage0

            basisKernelList.append(afwMath.FixedKernel(basisImage))

        order = 1  # 1 => up to linear
        spFunc = afwMath.PolynomialFunction2D(order)

        exactKernel = afwMath.LinearCombinationKernel(basisKernelList, spFunc)
        exactKernel.setSpatialParameters([[1.0, 0, 0],
                                          [0.0, 0.5 * 1e-2, 0.2e-2]])

        rand = afwMath.Random()  # make these tests repeatable by setting seed

        addNoise = True

        if addNoise:
            im = self.mi.getImage()
            afwMath.randomGaussianImage(im, rand)  # N(0, 1)
            im *= sd  # N(0, sd^2)
            del im

        xarr, yarr = [], []

        for x, y in [
            (20, 20),
            (60, 20),
            (30, 35),
            (50, 50),
            (20, 90),
            (70, 160),
            (25, 265),
            (75, 275),
            (85, 30),
            (50, 120),
            (70, 80),
            (60, 210),
            (20, 210),
        ]:
            xarr.append(x)
            yarr.append(y)

        for x, y in zip(xarr, yarr):
            dx = rand.uniform() - 0.5  # random (centered) offsets
            dy = rand.uniform() - 0.5

            k = exactKernel.getSpatialFunction(1)(
                x, y)  # functional variation of Kernel ...
            b = (k * sigma1**2 / ((1 - k) * sigma2**2)
                 )  # ... converted double Gaussian's "b"

            # flux = 80000 - 20*x - 10*(y/float(height))**2
            flux = 80000 * (1 + 0.1 * (rand.uniform() - 0.5))
            I0 = flux * (1 + b) / (2 * np.pi * (sigma1**2 + b * sigma2**2))
            for iy in range(y - self.ksize // 2, y + self.ksize // 2 + 1):
                if iy < 0 or iy >= self.mi.getHeight():
                    continue

                for ix in range(x - self.ksize // 2, x + self.ksize // 2 + 1):
                    if ix < 0 or ix >= self.mi.getWidth():
                        continue

                    II = I0 * psfVal(ix, iy, x + dx, y + dy, sigma1, sigma2, b)
                    Isample = rand.poisson(II) if addNoise else II
                    self.mi.image[ix, iy, afwImage.LOCAL] += Isample
                    self.mi.variance[ix, iy, afwImage.LOCAL] += II

        bbox = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(width, height))
        self.cellSet = afwMath.SpatialCellSet(bbox, 100)

        self.footprintSet = afwDetection.FootprintSet(
            self.mi, afwDetection.Threshold(100), "DETECTED")

        self.catalog = self.measure(self.footprintSet, self.exposure)

        for source in self.catalog:
            try:
                cand = measAlg.makePsfCandidate(source, self.exposure)
                self.cellSet.insertCandidate(cand)

            except Exception as e:
                print(e)
                continue
Exemple #25
0
 def _parallel_box(self, start, end):
     llc = lsstGeom.PointI(self.imaging.getMinX(), start)
     urc = lsstGeom.PointI(self.imaging.getMaxX(), end)
     return lsstGeom.BoxI(llc, urc)
def makeAmplifierList(ccd):
    """Construct a list of AmplifierBuilder objects
    """
    # Much of this will need to be filled in when we know it.
    assert len(ccd) > 0
    amp = list(ccd['amplifiers'].values())[0]

    rawBBox = makeBBoxFromList(amp['rawBBox'])  # total in file
    xRawExtent, yRawExtent = rawBBox.getDimensions()

    readCorners = {"LL": ReadoutCorner.LL,
                   "LR": ReadoutCorner.LR,
                   "UL": ReadoutCorner.UL,
                   "UR": ReadoutCorner.UR}

    amplifierList = []
    for name, amp in sorted(ccd['amplifiers'].items(), key=lambda x: x[1]['hdu']):
        amplifier = Amplifier.Builder()
        amplifier.setName(name)

        ix, iy = amp['ixy']
        perAmpData = amp['perAmpData']
        if perAmpData:
            x0, y0 = 0, 0           # origin of data within each amp image
        else:
            x0, y0 = ix*xRawExtent, iy*yRawExtent

        rawDataBBox = makeBBoxFromList(amp['rawDataBBox'])  # Photosensitive area
        xDataExtent, yDataExtent = rawDataBBox.getDimensions()
        amplifier.setBBox(geom.BoxI(
            geom.PointI(ix*xDataExtent, iy*yDataExtent), rawDataBBox.getDimensions()))

        rawBBox = makeBBoxFromList(amp['rawBBox'])
        rawBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawBBox(rawBBox)

        rawDataBBox = makeBBoxFromList(amp['rawDataBBox'])
        rawDataBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawDataBBox(rawDataBBox)

        rawSerialOverscanBBox = makeBBoxFromList(amp['rawSerialOverscanBBox'])
        rawSerialOverscanBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawHorizontalOverscanBBox(rawSerialOverscanBBox)

        rawParallelOverscanBBox = makeBBoxFromList(amp['rawParallelOverscanBBox'])
        rawParallelOverscanBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawVerticalOverscanBBox(rawParallelOverscanBBox)

        rawSerialPrescanBBox = makeBBoxFromList(amp['rawSerialPrescanBBox'])
        rawSerialPrescanBBox.shift(geom.ExtentI(x0, y0))
        amplifier.setRawPrescanBBox(rawSerialPrescanBBox)

        if perAmpData:
            amplifier.setRawXYOffset(geom.Extent2I(ix*xRawExtent, iy*yRawExtent))
        else:
            amplifier.setRawXYOffset(geom.Extent2I(0, 0))

        amplifier.setReadoutCorner(readCorners[amp['readCorner']])
        amplifier.setGain(amp['gain'])
        amplifier.setReadNoise(amp['readNoise'])
        amplifier.setSaturation(amp['saturation'])
        amplifier.setSuspectLevel(amp.get('suspect', np.nan))

        # flip data when assembling if needs be (e.g. data from the serial at the top of a CCD)
        flipX, flipY = amp.get("flipXY")

        amplifier.setRawFlipX(flipX)
        amplifier.setRawFlipY(flipY)
        # linearity placeholder stuff
        amplifier.setLinearityCoeffs([float(val) for val in amp['linearityCoeffs']])
        amplifier.setLinearityType(amp['linearityType'])
        amplifier.setLinearityThreshold(float(amp['linearityThreshold']))
        amplifier.setLinearityMaximum(float(amp['linearityMax']))
        amplifier.setLinearityUnits("DN")
        amplifierList.append(amplifier)
    return amplifierList