def initData(shape, coords, amplitudes=None, convolve=True):
    """Initialize data for the tests
    """

    B, Ny, Nx = shape
    K = len(coords)

    if amplitudes is None:
        amplitudes = np.ones((K, ))
    assert K == len(amplitudes)

    _seds = [
        np.arange(B, dtype=float),
        np.arange(B, dtype=float)[::-1],
        np.ones((B, ), dtype=float)
    ]
    seds = np.array([_seds[n % 3] * amplitudes[n] for n in range(K)],
                    dtype=np.float32)

    morphs = np.zeros((K, Ny, Nx), dtype=np.float32)
    for k, coord in enumerate(coords):
        morphs[k, coord[0], coord[1]] = 1
    images = seds.T.dot(morphs.reshape(K, -1)).reshape(shape)

    if convolve:
        psfRadius = 20
        psfShape = (2 * psfRadius + 1, 2 * psfRadius + 1)

        targetPsf = GaussianPsf(psfShape[1], psfShape[0], .9)
        targetPsfImage = targetPsf.computeImage().array

        psfs = [
            GaussianPsf(psfShape[1], psfShape[0], 1 + .2 * b) for b in range(B)
        ]
        psfImages = np.array([psf.computeImage().array for psf in psfs])
        psfImages /= psfImages.max(axis=(1, 2))[:, None, None]

        # Convolve the image with the psf in each channel
        # Use scipy.signal.convolve without using FFTs as a sanity check
        images = np.array([
            scipy.signal.convolve(img, psf, method="direct", mode="same")
            for img, psf in zip(images, psfImages)
        ])
        # Convolve the true morphology with the target PSF,
        # also using scipy.signal.convolve as a sanity check
        morphs = np.array([
            scipy.signal.convolve(m,
                                  targetPsfImage,
                                  method="direct",
                                  mode="same") for m in morphs
        ])
        morphs /= morphs.max()
        psfImages /= psfImages.sum(axis=(1, 2))[:, None, None]

    channels = range(len(images))
    return targetPsfImage, psfImages, images, channels, seds, morphs, targetPsf, psfs
Exemple #2
0
 def testMultiPlaneFitsReaders(self):
     """Run tests for MaskedImageFitsReader and ExposureFitsReader.
     """
     metadata = PropertyList()
     metadata.add("FIVE", 5)
     metadata.add("SIX", 6.0)
     wcs = makeSkyWcs(Point2D(2.5, 3.75),
                      SpherePoint(40.0 * degrees, 50.0 * degrees),
                      np.array([[1E-5, 0.0], [0.0, -1E-5]]))
     defineFilter("test_readers_filter", lambdaEff=470.0)
     calib = PhotoCalib(2.5E4)
     psf = GaussianPsf(21, 21, 8.0)
     polygon = Polygon(Box2D(self.bbox))
     apCorrMap = ApCorrMap()
     visitInfo = VisitInfo(exposureTime=5.0)
     transmissionCurve = TransmissionCurve.makeIdentity()
     coaddInputs = CoaddInputs(ExposureTable.makeMinimalSchema(),
                               ExposureTable.makeMinimalSchema())
     detector = DetectorWrapper().detector
     record = coaddInputs.ccds.addNew()
     record.setWcs(wcs)
     record.setPhotoCalib(calib)
     record.setPsf(psf)
     record.setValidPolygon(polygon)
     record.setApCorrMap(apCorrMap)
     record.setVisitInfo(visitInfo)
     record.setTransmissionCurve(transmissionCurve)
     record.setDetector(detector)
     for n, dtypeIn in enumerate(self.dtypes):
         with self.subTest(dtypeIn=dtypeIn):
             exposureIn = Exposure(self.bbox, dtype=dtypeIn)
             shape = exposureIn.image.array.shape
             exposureIn.image.array[:, :] = np.random.randint(low=1,
                                                              high=5,
                                                              size=shape)
             exposureIn.mask.array[:, :] = np.random.randint(low=1,
                                                             high=5,
                                                             size=shape)
             exposureIn.variance.array[:, :] = np.random.randint(low=1,
                                                                 high=5,
                                                                 size=shape)
             exposureIn.setMetadata(metadata)
             exposureIn.setWcs(wcs)
             exposureIn.setFilter(Filter("test_readers_filter"))
             exposureIn.setFilterLabel(
                 FilterLabel(physical="test_readers_filter"))
             exposureIn.setPhotoCalib(calib)
             exposureIn.setPsf(psf)
             exposureIn.getInfo().setValidPolygon(polygon)
             exposureIn.getInfo().setApCorrMap(apCorrMap)
             exposureIn.getInfo().setVisitInfo(visitInfo)
             exposureIn.getInfo().setTransmissionCurve(transmissionCurve)
             exposureIn.getInfo().setCoaddInputs(coaddInputs)
             exposureIn.setDetector(detector)
             with lsst.utils.tests.getTempFilePath(".fits") as fileName:
                 exposureIn.writeFits(fileName)
                 self.checkMaskedImageFitsReader(exposureIn, fileName,
                                                 self.dtypes[n:])
                 self.checkExposureFitsReader(exposureIn, fileName,
                                              self.dtypes[n:])
Exemple #3
0
    def setUp(self):
        np.random.seed(1)
        self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100))
        self.filters = ["G", "R", "I"]

        self.imgValue = 10
        images = [ImageF(self.bbox, self.imgValue) for f in self.filters]
        mImage = MultibandImage.fromImages(self.filters, images)

        self.Mask = Mask[MaskPixel]
        # Store the default mask planes for later use
        maskPlaneDict = self.Mask().getMaskPlaneDict()
        self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__)

        # reset so tests will be deterministic
        self.Mask.clearMaskPlaneDict()
        for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"):
            self.Mask.addMaskPlane(p)

        self.maskValue = self.Mask.getPlaneBitMask("BAD")
        singles = [self.Mask(self.bbox) for f in range(len(self.filters))]
        for n in range(len(singles)):
            singles[n].set(self.maskValue)
        mMask = MultibandMask.fromMasks(self.filters, singles)

        self.varValue = 1e-2
        images = [ImageF(self.bbox, self.varValue) for f in self.filters]
        mVariance = MultibandImage.fromImages(self.filters, images)

        self.kernelSize = 51
        self.psfs = [GaussianPsf(self.kernelSize, self.kernelSize, 4.0) for f in self.filters]
        self.psfImage = np.array([p.computeKernelImage().array for p in self.psfs])

        self.exposure = MultibandExposure(image=mImage, mask=mMask, variance=mVariance,
                                          psfs=self.psfs, filters=self.filters)
    def makeExposure(self, universalId):
        """Make a tiny exposure with exposure info set, but no pixels

        In particular, exposure info is set as a record in a table, so it can be recorded in a coadd
        """
        inputRecorder = self.coaddInputRecorder.makeCoaddTempExpRecorder(universalId, self.numExp)
        bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(100, 100), lsst.afw.geom.Extent2I(10, 10))

        detectorName = "detector {}".format(universalId)
        detector = lsst.afw.cameraGeom.testUtils.DetectorWrapper(name=detectorName, id=universalId).detector

        exp = lsst.afw.image.ExposureF(bbox)
        exp.setDetector(detector)

        expInfo = exp.getInfo()
        scale = 5.1e-5*lsst.afw.geom.degrees
        cdMatrix = lsst.afw.geom.makeCdMatrix(scale=scale)
        wcs = lsst.afw.geom.makeSkyWcs(
            crpix=lsst.afw.geom.Point2D(5, 5),
            crval=lsst.afw.geom.SpherePoint(10, 45, lsst.afw.geom.degrees),
            cdMatrix=cdMatrix,
        )
        expInfo.setWcs(wcs)
        expInfo.setPsf(GaussianPsf(5, 5, 2.5))
        expInfo.setPhotoCalib(lsst.afw.image.makePhotoCalibFromCalibZeroPoint(1.1e12, 2.2e10))
        expInfo.setApCorrMap(self.makeApCorrMap())
        expInfo.setValidPolygon(lsst.afw.geom.Polygon(lsst.afw.geom.Box2D(bbox).getCorners()))
        if self.version > 1:
            expInfo.setVisitInfo(self.makeVisitInfo())

        inputRecorder.addCalExp(calExp=exp, ccdId=universalId, nGoodPix=100)
        inputRecorder.finish(coaddTempExp=exp, nGoodPix=100)

        return exp
Exemple #5
0
    def testPsf(self):
        psfImage = self.exposure.computePsfKernelImage().array
        self.assertFloatsAlmostEqual(psfImage, self.psfImage)

        newPsfs = [GaussianPsf(self.kernelSize, self.kernelSize, 1.0) for f in self.filters]
        newPsfImage = [p.computeImage().array for p in newPsfs]
        for psf, exposure in zip(newPsfs, self.exposure.singles):
            exposure.setPsf(psf)
        psfImage = self.exposure.computePsfKernelImage()
        self.assertFloatsAlmostEqual(psfImage.array, newPsfImage)

        psfImage = self.exposure.computePsfImage().array[0]
        self.assertFloatsAlmostEqual(psfImage, self.exposure["G"].getPsf().computeImage().array)
Exemple #6
0
def loadData(psfSigma=1.5):
    """Prepare the data we need to run the example"""

    # Load sample input from disk
    mypath = lsst.utils.getPackageDir('afwdata')
    imFile = os.path.join(mypath, "CFHT", "D4",
                          "cal-53535-i-797722_small_1.fits")

    exposure = afwImage.ExposureF(imFile)
    # add a filter
    afwImage.Filter.define(afwImage.FilterProperty(FilterName, 600, True))
    exposure.setFilter(afwImage.Filter(FilterName))
    # add a simple Gaussian PSF model
    psfModel = GaussianPsf(11, 11, psfSigma)
    exposure.setPsf(psfModel)

    return exposure
Exemple #7
0
    def makeExposure(self, universalId):
        """Make a tiny exposure with exposure info set, but no pixels

        In particular, exposure info is set as a record in a table, so it can be recorded in a coadd
        """
        inputRecorder = self.coaddInputRecorder.makeCoaddTempExpRecorder(
            universalId, self.numExp)
        bbox = lsst.afw.geom.Box2I(lsst.afw.geom.Point2I(100, 100),
                                   lsst.afw.geom.Extent2I(10, 10))

        detectorName = "detector {}".format(universalId)
        detector = lsst.afw.cameraGeom.testUtils.DetectorWrapper(
            name=detectorName, id=universalId).detector

        exp = lsst.afw.image.ExposureF(bbox)
        exp.setDetector(detector)

        expInfo = exp.getInfo()
        wcs = lsst.afw.image.makeWcs(
            IcrsCoord(10 * lsst.afw.geom.degrees, 45 * lsst.afw.geom.degrees),
            lsst.afw.geom.Point2D(5, 5),
            5.1e-5,
            0,
            0,
            -5.1e-5,  # CD: 11, 12, 21, 22
        )
        expInfo.setWcs(wcs)
        expInfo.setPsf(GaussianPsf(5, 5, 2.5))
        calib = lsst.afw.image.Calib()
        calib.setFluxMag0(1.1e12, 2.2e10)
        expInfo.setCalib(calib)
        expInfo.setApCorrMap(self.makeApCorrMap())
        expInfo.setValidPolygon(Polygon(
            lsst.afw.geom.Box2D(bbox).getCorners()))
        if self.version > 1:
            expInfo.setVisitInfo(self.makeVisitInfo())

        inputRecorder.addCalExp(calExp=exp, ccdId=universalId, nGoodPix=100)
        inputRecorder.finish(coaddTempExp=exp, nGoodPix=100)

        return exp
Exemple #8
0
 def setUp(self):
     self.pgps = []
     self.gps = []
     for width, height, sigma in [(5, 5, 1.1), (5, 3, 1.2), (7, 7, 1.3)]:
         self.pgps.append(PyGaussianPsf(width, height, sigma))
         self.gps.append(GaussianPsf(width, height, sigma))
Exemple #9
0
    def testComputeExposureSummary(self):
        """Make a fake exposure and background and compute summary.
        """
        np.random.seed(12345)

        # Make an exposure with a noise image
        exposure = afwImage.ExposureF(100, 100)
        skySigma = 10.0
        exposure.getImage().getArray()[:, :] = np.random.normal(0.0,
                                                                skySigma,
                                                                size=(100,
                                                                      100))
        exposure.getVariance().getArray()[:, :] = skySigma**2.

        # Set the visitInfo
        date = DateTime(date=59234.7083333334, system=DateTime.DateSystem.MJD)
        observatory = Observatory(-70.7366 * lsst.geom.degrees,
                                  -30.2407 * lsst.geom.degrees, 2650.)
        visitInfo = afwImage.VisitInfo(exposureTime=10.0,
                                       date=date,
                                       observatory=observatory)
        exposure.getInfo().setVisitInfo(visitInfo)

        # Install a Gaussian PSF
        psfSize = 2.0
        psf = GaussianPsf(5, 5, psfSize)
        exposure.setPsf(psf)

        # Install a simple WCS
        scale = 0.2 * lsst.geom.arcseconds
        raCenter = 300.0 * lsst.geom.degrees
        decCenter = 0.0 * lsst.geom.degrees
        cdMatrix = makeCdMatrix(scale=scale)
        skyWcs = makeSkyWcs(crpix=exposure.getBBox().getCenter(),
                            crval=lsst.geom.SpherePoint(raCenter, decCenter),
                            cdMatrix=cdMatrix)
        exposure.setWcs(skyWcs)

        # Install a simple photoCalib
        photoCalib = afwImage.PhotoCalib(calibrationMean=0.3)
        zp = 2.5 * np.log10(photoCalib.getInstFluxAtZeroMagnitude())
        exposure.setPhotoCalib(photoCalib)

        # Compute the background image
        bgGridSize = 10
        bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE)
        bctrl.setNxSample(
            int(exposure.getMaskedImage().getWidth() / bgGridSize) + 1)
        bctrl.setNySample(
            int(exposure.getMaskedImage().getHeight() / bgGridSize) + 1)
        backobj = afwMath.makeBackground(exposure.getMaskedImage().getImage(),
                                         bctrl)
        background = afwMath.BackgroundList()
        background.append(backobj)

        # Run the task
        expSummaryTask = ComputeExposureSummaryStatsTask()
        summary = expSummaryTask.run(exposure, None, background)

        # Test the outputs
        self.assertFloatsAlmostEqual(summary.psfSigma, psfSize)
        self.assertFloatsAlmostEqual(summary.psfIxx, psfSize**2.)
        self.assertFloatsAlmostEqual(summary.psfIyy, psfSize**2.)
        self.assertFloatsAlmostEqual(summary.psfIxy, 0.0)
        self.assertFloatsAlmostEqual(summary.psfArea, 23.088975164455444)

        delta = (scale * 50).asDegrees()
        for a, b in zip(summary.raCorners, [
                raCenter.asDegrees() + delta,
                raCenter.asDegrees() - delta,
                raCenter.asDegrees() - delta,
                raCenter.asDegrees() + delta
        ]):
            self.assertFloatsAlmostEqual(a, b, atol=1e-10)
        for a, b in zip(summary.decCorners, [
                decCenter.asDegrees() - delta,
                decCenter.asDegrees() - delta,
                decCenter.asDegrees() + delta,
                decCenter.asDegrees() + delta
        ]):
            self.assertFloatsAlmostEqual(a, b, atol=1e-10)

        self.assertFloatsAlmostEqual(summary.ra,
                                     raCenter.asDegrees(),
                                     atol=1e-10)
        self.assertFloatsAlmostEqual(summary.decl,
                                     decCenter.asDegrees(),
                                     atol=1e-10)

        self.assertFloatsAlmostEqual(summary.zeroPoint, zp)

        # Need to compare background level and noise
        # These are only approximately 0+/-10 because of the small image
        self.assertFloatsAlmostEqual(summary.skyBg, -0.079, atol=1e-3)

        self.assertFloatsAlmostEqual(summary.meanVar, skySigma**2.)

        self.assertFloatsAlmostEqual(summary.zenithDistance,
                                     30.57112,
                                     atol=1e-5)
Exemple #10
0
def makeMockVisitSummary(visit,
                         ra_center=0.0,
                         dec_center=-45.0,
                         physical_filter='TEST-I',
                         band='i',
                         mjd=59234.7083333334,
                         psf_sigma=3.0,
                         zenith_distance=45.0,
                         zero_point=30.0,
                         sky_background=100.0,
                         sky_noise=10.0,
                         mean_var=100.0,
                         exposure_time=100.0,
                         detector_size=200,
                         pixel_scale=0.2):
    """Make a mock visit summary catalog.

    This will contain two square detectors with the same metadata,
    with a small (20 pixel) gap between the detectors.  There is no
    rotation, as each detector is simply offset in RA from the
    specified boresight.

    Parameters
    ----------
    visit : `int`
        Visit number.
    ra_center : `float`
        Right ascension of the center of the "camera" boresight (degrees).
    dec_center : `float`
        Declination of the center of the "camera" boresight (degrees).
    physical_filter : `str`
        Arbitrary name for the physical filter.
    band : `str`
        Name of the associated band.
    mjd : `float`
        Modified Julian Date.
    psf_sigma : `float`
        Sigma width of Gaussian psf.
    zenith_distance : `float`
        Distance from zenith of the visit (degrees).
    zero_point : `float`
        Constant zero point for the visit (magnitudes).
    sky_background : `float`
        Background level for the visit (counts).
    sky_noise : `float`
        Noise level for the background of the visit (counts).
    mean_var : `float`
        Mean of the variance plane of the visit (counts).
    exposure_time : `float`
        Exposure time of the visit (seconds).
    detector_size : `int`
        Size of each square detector in the visit (pixels).
    pixel_scale : `float`
        Size of the pixel in arcseconds per pixel.

    Returns
    -------
    visit_summary : `lsst.afw.table.ExposureCatalog`
    """
    # We are making a 2 detector "camera"
    n_detector = 2

    schema = ConsolidateVisitSummaryTask()._makeVisitSummarySchema()
    visit_summary = afwTable.ExposureCatalog(schema)
    visit_summary.resize(n_detector)

    bbox = geom.Box2I(x=geom.IntervalI(min=0, max=detector_size - 1),
                      y=geom.IntervalI(min=0, max=detector_size - 1))

    for detector_id in range(n_detector):
        row = visit_summary[detector_id]

        row['id'] = detector_id
        row.setBBox(bbox)
        row['visit'] = visit
        row['physical_filter'] = physical_filter
        row['band'] = band
        row['zenithDistance'] = zenith_distance
        row['zeroPoint'] = zero_point
        row['skyBg'] = sky_background
        row['skyNoise'] = sky_noise
        row['meanVar'] = mean_var

        # Generate a photocalib
        instFluxMag0 = 10.**(zero_point / 2.5)
        row.setPhotoCalib(
            afwImage.makePhotoCalibFromCalibZeroPoint(instFluxMag0))

        # Generate a WCS and set values accordingly
        crpix = geom.Point2D(detector_size / 2., detector_size / 2.)
        # Create a 20 pixel gap between the two detectors (each offset 10 pixels).
        if detector_id == 0:
            delta_ra = -1.0 * ((detector_size + 10) * pixel_scale /
                               3600.) / np.cos(np.deg2rad(dec_center))
            delta_dec = 0.0
        elif detector_id == 1:
            delta_ra = ((detector_size + 10) * pixel_scale / 3600.) / np.cos(
                np.deg2rad(dec_center))
            delta_dec = 0.0
        crval = geom.SpherePoint(ra_center + delta_ra, dec_center + delta_dec,
                                 geom.degrees)
        cd_matrix = afwGeom.makeCdMatrix(scale=pixel_scale * geom.arcseconds,
                                         orientation=0.0 * geom.degrees)
        wcs = afwGeom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cd_matrix)
        row.setWcs(wcs)

        sph_pts = wcs.pixelToSky(geom.Box2D(bbox).getCorners())
        row['raCorners'] = np.array(
            [float(sph.getRa().asDegrees()) for sph in sph_pts])
        row['decCorners'] = np.array(
            [float(sph.getDec().asDegrees()) for sph in sph_pts])
        sph_pt = wcs.pixelToSky(bbox.getCenter())
        row['ra'] = sph_pt.getRa().asDegrees()
        row['decl'] = sph_pt.getDec().asDegrees()

        # Generate a visitInfo.
        # This does not need to be consistent with the zenith angle in the table,
        # it just needs to be valid and have sufficient information to compute
        # exposure time and parallactic angle.
        date = DateTime(date=mjd, system=DateTime.DateSystem.MJD)
        visit_info = afwImage.VisitInfo(
            exposureId=visit,
            exposureTime=exposure_time,
            date=date,
            darkTime=0.0,
            boresightRaDec=geom.SpherePoint(ra_center, dec_center,
                                            geom.degrees),
            era=45.1 * geom.degrees,
            observatory=Observatory(11.1 * geom.degrees, 0.0 * geom.degrees,
                                    0.333),
            boresightRotAngle=0.0 * geom.degrees,
            rotType=afwImage.RotType.SKY)
        row.setVisitInfo(visit_info)

        # Generate a PSF and set values accordingly
        psf = GaussianPsf(15, 15, psf_sigma)
        row.setPsf(psf)
        psfAvgPos = psf.getAveragePosition()
        shape = psf.computeShape(psfAvgPos)
        row['psfSigma'] = psf.getSigma()
        row['psfIxx'] = shape.getIxx()
        row['psfIyy'] = shape.getIyy()
        row['psfIxy'] = shape.getIxy()
        row['psfArea'] = shape.getArea()

    return visit_summary