def setUp(self): # Test geometry: # # -100,99 99,99 # +--------------------+ # |AAAAAAAAAACCCCCDDDDD| A == only in epoch A # |AAAAAAAAAACCCCCDDDDD| B == only in epoch B # |AAAAAAAAAACCCCCDDDDD| C == in both epoch A and epoch B # |AAAAAAAAAACCCCCDDDDD| D == in epoch A; in B's bbox but outside its ValidPolygon # |AAAAAAAAAACCCCCDDDDD| # | BBBBBBBBBB| All WCSs have the same CRVAL and CD. # | BBBBBBBBBB| # | BBBBBBBBBB| Coadd has CRPIX=(0, 0) # | BBBBBBBBBB| Epoch A has CRPIX=(0, -50) # | BBBBBBBBBB| Epoch B has CRPIX=(-50, 0) # +--------------------+ # -100,-100 99,-100 # self.rng = np.random.RandomState(50) crval = SpherePoint(45.0, 45.0, degrees) cdMatrix = makeCdMatrix(scale=5E-5 * degrees, flipX=True) self.wcsCoadd = makeSkyWcs(crpix=Point2D(0.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.wcsA = makeSkyWcs(crpix=Point2D(0.0, -50.0), crval=crval, cdMatrix=cdMatrix) self.wcsB = makeSkyWcs(crpix=Point2D(-50.0, 0.0), crval=crval, cdMatrix=cdMatrix) self.bboxCoadd = Box2I(Point2I(-100, -100), Point2I(99, 99)) self.bboxA = Box2I(Point2I(-100, -50), Point2I(99, 49)) self.bboxB = Box2I(Point2I(-50, -100), Point2I(49, 99)) self.polygonA = None polygonD = Polygon(Box2D(Box2I(Point2I(0, 0), Point2I(49, 99)))) self.polygonB, = polygonD.symDifference(Polygon(Box2D(self.bboxB))) self.curveA = makeRandomTransmissionCurve(self.rng) self.curveB = makeRandomTransmissionCurve(self.rng) self.weightA = 0.6 self.weightB = 0.2 schema = ExposureTable.makeMinimalSchema() weightKey = schema.addField("weight", type=float, doc="relative weight of image in Coadd") catalog = ExposureCatalog(schema) recordA = catalog.addNew() recordA[weightKey] = self.weightA recordA.setWcs(self.wcsA) recordA.setValidPolygon(self.polygonA) recordA.setBBox(self.bboxA) recordA.setTransmissionCurve(self.curveA) recordB = catalog.addNew() recordB[weightKey] = self.weightB recordB.setWcs(self.wcsB) recordB.setValidPolygon(self.polygonB) recordB.setBBox(self.bboxB) recordB.setTransmissionCurve(self.curveB) self.curveCoadd = makeCoaddTransmissionCurve(self.wcsCoadd, catalog)
def setUp(self): xy0 = Point2I(12345, 67890) # xy0 for image dims = Extent2I(2345, 2345) # Dimensions of image box = Box2I(xy0, dims) # Bounding box of image sigma = 3.21 # PSF sigma buffer = 4.0 # Buffer for star centers around edge nSigmaForKernel = 5.0 # Number of PSF sigmas for kernel sky = 12345.6 # Sky level numStars = 100 # Number of stars noise = np.sqrt(sky) * np.pi * sigma**2 # Poisson noise per PSF faint = 1.0 * noise # Faintest level for star fluxes bright = 100.0 * noise # Brightest level for star fluxes starBox = Box2I(box) # Area on image in which we can put star centers starBox.grow(-int(buffer * sigma)) scale = 1.0e-5 * degrees # Pixel scale np.random.seed(12345) stars = [(xx, yy, ff, sigma) for xx, yy, ff in zip( np.random.uniform(starBox.getMinX(), starBox.getMaxX(), numStars), np.random.uniform(starBox.getMinY(), starBox.getMaxY(), numStars), np.linspace(faint, bright, numStars))] self.exposure = plantSources(box, 2 * int(nSigmaForKernel * sigma) + 1, sky, stars, True) self.exposure.setWcs( makeSkyWcs(crpix=Point2D(0, 0), crval=SpherePoint(0, 0, degrees), cdMatrix=makeCdMatrix(scale=scale))) # Make a large area of extra background; we should be robust against it # Unfortunately, some tuning is required here to get something challenging but not impossible: # * A very large box will cause failures because the "extra" and the "normal" are reversed. # * A small box will not be challenging because it's simple to clip out. # * A large value will cause failures because it produces large edges in background-subtrction that # broaden flux distributions. # * A small value will not be challenging because it has little effect. extraBox = Box2I(xy0 + Extent2I(345, 456), Extent2I(1234, 1234)) # Box for extra background extraValue = 0.5 * noise # Extra background value to add in self.exposure.image[extraBox, PARENT] += extraValue self.config = DynamicDetectionTask.ConfigClass() self.config.skyObjects.nSources = 300 self.config.reEstimateBackground = False self.config.doTempWideBackground = True self.config.thresholdType = "pixel_stdev" # Relative tolerance for tweak factor # Not sure why this isn't smaller; maybe due to use of Poisson instead of Gaussian noise? self.rtol = 0.1
def setUp(self): # Set up a Coadd with CoaddInputs tables that have blank filter columns to be filled # in by later test code. self.coadd = ExposureF(30, 90) # WCS is arbitrary, since it'll be the same for all images wcs = makeSkyWcs(crpix=Point2D(0, 0), crval=SpherePoint(45.0, 45.0, degrees), cdMatrix=makeCdMatrix(scale=0.17 * degrees)) self.coadd.setWcs(wcs) schema = ExposureCatalog.Table.makeMinimalSchema() self.filterKey = schema.addField("filter", type=str, doc="", size=16) weightKey = schema.addField("weight", type=float, doc="") # First input image covers the first 2/3, second covers the last 2/3, so they # overlap in the middle 1/3. inputs = ExposureCatalog(schema) self.input1 = inputs.addNew() self.input1.setId(1) self.input1.setBBox(Box2I(Point2I(0, 0), Point2I(29, 59))) self.input1.setWcs(wcs) self.input1.set(weightKey, 2.0) self.input2 = inputs.addNew() self.input2.setId(2) self.input2.setBBox(Box2I(Point2I(0, 30), Point2I(29, 89))) self.input2.setWcs(wcs) self.input2.set(weightKey, 3.0) # Use the same catalog for visits and CCDs since the algorithm we're testing only cares # about CCDs. self.coadd.getInfo().setCoaddInputs(CoaddInputs(inputs, inputs)) # Set up a catalog with centroids and a FilterFraction plugin. # We have one record in each region (first input only, both inputs, second input only) schema = SourceCatalog.Table.makeMinimalSchema() centroidKey = Point2DKey.addFields(schema, "centroid", doc="position", unit="pixel") schema.getAliasMap().set("slot_Centroid", "centroid") self.plugin = FilterFractionPlugin( config=FilterFractionPlugin.ConfigClass(), schema=schema, name="subaru_FilterFraction", metadata=PropertyList()) catalog = SourceCatalog(schema) self.record1 = catalog.addNew() self.record1.set(centroidKey, Point2D(14.0, 14.0)) self.record12 = catalog.addNew() self.record12.set(centroidKey, Point2D(14.0, 44.0)) self.record2 = catalog.addNew() self.record2.set(centroidKey, Point2D(14.0, 74.0))
def makeRandomPoint(self, *args, **kwds): """Draw a random Point2D within a Box2I. All arguments are forwarded directly to the Box2I constructor, allowing the caller to pass a fully-constructed Box2I, a (Point2I, Point2I) pair, or a (Point2I, Extent2I) pair. """ bboxD = Box2D(Box2I(*args, **kwds)) return bboxD.getMin() + Extent2D(bboxD.getWidth() * self.rng.rand(), bboxD.getHeight() * self.rng.rand())
def readFits(cls, path): """Read an external detrended image and create an LSST Exposure object from it. Any significant processing (e.g. pixel interpolation) should probably be done in a ExternalIsrTask instead of here so it can be done once and saved, instead of being done every time the image is loaded. THIS METHOD IS INCOMPLETE; IT MUST BE MODIFIED ACCORDING TO THE FORMAT OF THE DATA BEING LOADED. """ directory, filename = os.path.split(path) match = cls.EXTERNAL_REGEX.match(filename) camera = cls.getCameraFromVisit(match.group("visit")) # Customize the code below based on the camera determined above. # To support more than one camera it may be useful to delegate # to other methods that are specific to certain cameras. # Read the actual image in from the given path using e.g. astropy, # and use it to fill in various arrays below. bbox = Box2I(Point2I(0, 0), Extent2I(..., ...)) # width, height result = ExposureF(bbox) # main image, as a [y, x] numpy.float32 array result.image.array = ... # variance image, as a [y, x] numpy.float32 array result.variance.array = ... # This example includes masking NaN pixels as NO_DATA and pixels above # 1E5 counts as SAT. External information about where bad pixels # should be preferred when available, and obviously that saturation # threshold is just an example (saturation should actually be # determined before flat-fielding, of course). # Interpolating these bad pixels is handled by ExternalIsrTask. noDataBitMask = result.mask.getPlaneBitMask("NO_DATA") satBitMask = result.mask.getPlaneBitMask("SAT") result.mask.array |= noDataBitMask * np.isnan(result.image.array) result.mask.array |= satBitMask * (result.image.array > 1E5) # If you have a better guess at the PSF, we can find a way to use it. # But it'd be a good idea to at least put this in with a guess at the # seeing (RMS in pixels). result.setPsf(SingleGaussianPsf(seeingRMS)) # Add a guess for the WCS, in this case assuming it's in the FITS # header of the first HDU. Need to have something here, even if it # isn't very good (e.g. whatever comes from the telescope). metadata = readMetadata(filename) wcs = SkyWcs(metadata) result.setWcs(wcs) return result
def extractCtorArgs(md): wcs = makeSkyWcs(makePropertyListFromDict(md)) kwds = { "pixelToIwc": getPixelToIntermediateWorldCoords(wcs), "bbox": Box2D(Box2I(Point2I(0, 0), Extent2I(md["NAXES1"], md["NAXES2"]))), "crpix": Point2D(md["CRPIX1"] - 1.0, md["CRPIX2"] - 1.0), # -1 for LSST vs. FITS conventions "cd": np.array([[md["CD1_1"], md["CD1_2"]], [md["CD2_1"], md["CD2_2"]]]), } return kwds
def testBasics(self): """Test detection and measurement on simple synthesized data """ bbox = Box2I(Point2I(256, 100), Extent2I(128, 127)) minCounts = 5000 maxCounts = 50000 starSigma = 1.5 numX = 5 numY = 5 coordList = self.makeCoordList( bbox=bbox, numX=numX, numY=numY, minCounts=minCounts, maxCounts=maxCounts, sigma=starSigma, ) kwid = 11 # kernel width sky = 2000 # create an exposure without a Wcs; add the Wcs later exposure = plantSources(bbox=bbox, kwid=kwid, sky=sky, coordList=coordList, addPoissonNoise=True) schema = SourceTable.makeMinimalSchema() config = DetectAndMeasureTask.ConfigClass() task = DetectAndMeasureTask(config=config, schema=schema) butler = Butler(root=InputDir) dataRef = butler.dataRef("calexp", dataId=dict(visit=1)) wcs = dataRef.get("raw").getWcs() exposure.setWcs(wcs) exposureIdInfo = dataRef.get("expIdInfo") taskRes = task.run(exposure=exposure, exposureIdInfo=exposureIdInfo) self.assertEqual(len(taskRes.sourceCat), numX * numY) schema = taskRes.sourceCat.schema centroidFlagKey = schema.find("slot_Centroid_flag").getKey() parentKey = schema.find("parent").getKey() psfFluxFlagKey = schema.find("slot_PsfFlux_flag").getKey() psfFluxKey = schema.find("slot_PsfFlux_flux").getKey() for src in taskRes.sourceCat: self.assertFalse(src.get(centroidFlagKey)) # centroid found self.assertEqual(src.get(parentKey), 0) # not debelended self.assertFalse(src.get(psfFluxFlagKey)) # flux measured self.assertGreater(src.get(psfFluxKey), 4000) # flux sane
def makeCasuWfcam(): path = os.path.join(getPackageDir("obs_ukirt"), "casuWfcam", "camera") for detNum, (gain, sat) in enumerate(zip(GAIN, SATURATION), 1): det = AmpInfoCatalog(AmpInfoTable.makeMinimalSchema()) amp = det.addNew() amp.setName(str(detNum)) amp.setBBox(Box2I()) amp.setGain(gain) amp.setReadNoise(READNOISE) amp.setSaturation(sat) # amp.setSuspectLevel(float("nan")) amp.setReadoutCorner(LL) amp.setLinearityType("none") amp.setHasRawInfo(False) det.writeFits(os.path.join(path, "%d.fits" % (detNum, )))
def setUp(self): self.crpix = Point2D(100, 100) self.crvalList = [ SpherePoint(0 * degrees, 45 * degrees), SpherePoint(0.00001 * degrees, 45 * degrees), SpherePoint(359.99999 * degrees, 45 * degrees), SpherePoint(30 * degrees, 89.99999 * degrees), SpherePoint(30 * degrees, -89.99999 * degrees), ] self.orientationList = [ 0 * degrees, 0.00001 * degrees, -0.00001 * degrees, -45 * degrees, 90 * degrees, ] self.scale = 1.0 * arcseconds self.tinyPixels = 1.0e-10 self.tinyAngle = 1.0e-10 * radians self.bbox = Box2I(Point2I(-1000, -1000), Extent2I(2000, 2000)) # arbitrary but reasonable
def setUp(self): # ImageL (uint64) is not supported by FITS standard, needs special tests self.IntegerImages = (afwImage.ImageU, afwImage.ImageI) self.FloatImages = (afwImage.ImageF, afwImage.ImageD) self.bbox = Box2I(minimum=Point2I(3, 4), maximum=Point2I(9, 7))