def summarizeVisit(butler, *, exp=None, extendedSummary=False, **kwargs): from astroquery.simbad import Simbad import astropy.units as u from astropy.time import Time from astropy.coordinates import SkyCoord, EarthLocation, AltAz def _airMassFromrRawMd(md): auxTelLocation = EarthLocation(lat=-30.244639 * u.deg, lon=-70.749417 * u.deg, height=2663 * u.m) time = Time(md['DATE-OBS']) skyLocation = SkyCoord(md['RASTART'], md['DECSTART'], unit=u.deg) altAz = AltAz(obstime=time, location=auxTelLocation) observationAltAz = skyLocation.transform_to(altAz) return observationAltAz.secz.value items = ["OBJECT", "expTime", "FILTER", "imageType"] obj, expTime, filterCompound, imageType = butler.queryMetadata( 'raw', items, **kwargs)[0] filt, grating = filterCompound.split('~') rawMd = butler.get('raw_md', **kwargs) airmass = _airMassFromrRawMd(rawMd) print(f"Object name: {obj}") print(f"expTime: {expTime}s") print(f"imageType: {imageType}") print(f"Filter: {filt}") print(f"Grating: {grating}") print(f"Airmass: {airmass:.3f}") if imageType not in ['BIAS', 'FLAT', 'DARK']: simbadObj = Simbad.query_object(obj) if simbadObj is None: print(f"Failed to find {obj} in Simbad.") else: assert (len(simbadObj.as_array()) == 1) raStr = simbadObj[0]['RA'] decStr = simbadObj[0]['DEC'] skyLocation = SkyCoord(raStr, decStr, unit=(u.hourangle, u.degree), frame='icrs') raRad, decRad = skyLocation.ra.rad, skyLocation.dec.rad print(f"obj RA (str): {raStr}") print(f"obj DEC (str): {decStr}") print(f"obj RA (rad): {raRad:5f}") print(f"obj DEC (rad): {decRad:5f}") print(f"obj RA (deg): {raRad*180/math.pi:5f}") print(f"obj DEC (deg): {decRad*180/math.pi:5f}") if exp is not None: # calc source coords from exp wcs ra = geom.Angle(raRad) dec = geom.Angle(decRad) targetLocation = geom.SpherePoint(ra, dec) pixCoord = exp.getWcs().skyToPixel(targetLocation) print(exp.getWcs()) print(f"Source location: {pixCoord} using exp provided") else: # try to find one, but not too hard datasetTypes = ['calexp', 'quickLookExp', 'postISRCCD'] for datasetType in datasetTypes: wcs = None typeUsed = None try: wcs = butler.get(datasetType + '_wcs', **kwargs) typeUsed = datasetType break except butlerExcept.NoResults: pass if wcs is not None: ra = geom.Angle(raRad) dec = geom.Angle(decRad) targetLocation = geom.SpherePoint(ra, dec) pixCoord = wcs.skyToPixel(targetLocation) print(wcs) print(f"Source location: {pixCoord} using {typeUsed}") if extendedSummary: print('\n--- Extended Summary ---') ranIsr = False if exp is None: print("Running isr to compute image stats...") # catch all the ISR chat # logRedirection1 = LogRedirect(1, open(os.devnull, 'w')) # logRedirection2 = LogRedirect(2, open(os.devnull, 'w')) # import ipdb as pdb; pdb.set_trace() from lsst.ip.isr.isrTask import IsrTask isrConfig = IsrTask.ConfigClass() isrConfig.doLinearize = False isrConfig.doBias = False isrConfig.doFlat = False isrConfig.doDark = False isrConfig.doFringe = False isrConfig.doDefect = False isrConfig.doWrite = False isrTask = IsrTask(config=isrConfig) dataRef = butler.dataRef('raw', **kwargs) exp = isrTask.runDataRef(dataRef).exposure wcs = exp.getWcs() ranIsr = True # logRedirection1.finish() # end re-direct # logRedirection2.finish() # end re-direct print(wcs) if simbadObj and ranIsr: ra = geom.Angle(raRad) dec = geom.Angle(decRad) targetLocation = geom.SpherePoint(ra, dec) pixCoord = wcs.skyToPixel(targetLocation) print( f"Source location: {pixCoord} using postISR just-reconstructed wcs" ) print( f'\nImage stats from {"just-constructed" if ranIsr else "provided"} exp:\n' ) print(f'Image mean: {np.mean(exp.image.array):.2f}') print(f'Image median: {np.median(exp.image.array):.2f}') print(f'Image min: {np.min(exp.image.array):.2f}') print(f'Image max: {np.max(exp.image.array):.2f}') # TODO: quartiles/percentiles here # number of masked pixels, saturated pixels print() print(f'BAD pixels: {countPixels(exp.maskedImage, "BAD")}') print(f'SAT pixels: {countPixels(exp.maskedImage, "SAT")}') print(f'CR pixels: {countPixels(exp.maskedImage, "CR")}') print(f'INTRP pixels: {countPixels(exp.maskedImage, "INTRP")}') print(f'DETECTED pixels: {countPixels(exp.maskedImage, "DETECTED")}') # detector = exp.getDetector() visitInfo = exp.getInfo().getVisitInfo() rotAngle = visitInfo.getBoresightRotAngle() boresight = visitInfo.getBoresightRaDec() md = butler.get('raw_md', **kwargs) print("\n From VisitInfo:") print(f"boresight: {boresight}") print(f"rotAngle: {rotAngle}") print(f" → {rotAngle.asDegrees():.4f} deg") print("\n From raw_md:") print(f"ROTPA: {md['ROTPA']} deg") print(f" → {(md['ROTPA']*math.pi/180):.6f} rad")
def setUp(self): """Constructs a CCD with two amplifiers and prepares for ISR""" np.random.seed(12345) baseValue = 100.0 gain = 1.0 readNoise = 123456789.0 saturation = 987654321.0 height = 234 imageSize = Extent2I(123, height) overscanSize = Extent2I(16, height) self.sigma = 1.234 # Set up the various regions overscan1 = Box2I(Point2I(0, 0), overscanSize) image1 = Box2I(Point2I(overscanSize[0], 0), imageSize) image2 = Box2I(Point2I(overscanSize[0] + imageSize[0], 0), imageSize) overscan2 = Box2I(Point2I(overscanSize[0] + 2 * imageSize[0], 0), overscanSize) leftBox = Box2I( overscan1.getMin(), Extent2I(overscan1.getWidth() + image1.getWidth(), height)) rightBox = Box2I( image2.getMin(), Extent2I(image2.getWidth() + overscan2.getWidth(), height)) target1 = Box2I(Point2I(0, 0), imageSize) target2 = Box2I(Point2I(image1.getWidth(), 0), imageSize) # Set the pixels exposure = ExposureF( Box2I(Point2I(0, 0), Extent2I(imageSize[0] * 2 + overscanSize[0] * 2, height))) yy = np.arange(0, height, 1, dtype=np.float32) leftImage = ExposureF(exposure, leftBox) leftImage.image.array[:] = baseValue + yy[:, np.newaxis] rightImage = ExposureF(exposure, rightBox) rightImage.image.array[:] = baseValue - yy[:, np.newaxis] leftOverscan = ExposureF(exposure, overscan1) leftOverscan.image.array += np.random.normal( 0.0, self.sigma, leftOverscan.image.array.shape) rightOverscan = ExposureF(exposure, overscan2) rightOverscan.image.array += np.random.normal( 0.0, self.sigma, leftOverscan.image.array.shape) exposure.mask.array[:] = 0.0 exposure.variance.array[:] = np.nan # Construct the detectors amp1 = makeAmplifier("left", target1, image1, overscan1, gain, readNoise, saturation) amp2 = makeAmplifier("right", target2, image2, overscan2, gain, readNoise, saturation) ccdBox = Box2I(Point2I(0, 0), Extent2I(image1.getWidth() + image2.getWidth(), height)) camBuilder = cameraGeom.Camera.Builder("fakeCam") detBuilder = camBuilder.add("detector", 1) detBuilder.setSerial("det1") detBuilder.setBBox(ccdBox) detBuilder.setPixelSize(Extent2D(1.0, 1.0)) detBuilder.setOrientation(cameraGeom.Orientation()) detBuilder.append(amp1) detBuilder.append(amp2) cam = camBuilder.finish() exposure.setDetector(cam.get('detector')) header = PropertyList() header.add("EXPTIME", 0.0) exposure.getInfo().setVisitInfo(VisitInfo(header)) self.exposure = exposure self.config = IsrTask.ConfigClass() # Disable everything we don't care about self.config.doBias = False self.config.doDark = False self.config.doFlat = False self.config.doFringe = False self.config.doDefect = False self.config.doWrite = False self.config.expectWcs = False self.config.doLinearize = False self.config.doCrosstalk = False self.config.doBrighterFatter = False self.config.doAttachTransmissionCurve = False self.config.doAssembleCcd = False self.config.doNanMasking = False self.config.doInterpolate = False self.config.maskNegativeVariance = False # This runs on mocks. # Set the things that match our test setup self.config.overscan.fitType = "CHEB" self.config.overscan.order = 1 self.config.doEmpiricalReadNoise = True self.task = IsrTask(config=self.config)