#!/usr/bin/env python3 # # Copyright (c) 2017 Weitian LI # MIT license """ Further process the reprocessed evt2 file to make a cleaned one for later scientific analysis. The following steps are carried out: 1. Filter out the chips of interest; 2. Detect (point) sources, visually check and manually update; 3. Remove the updated sources; 4. Extract light curve of the background regions (away from the object); 5. Check and clip the light curve to create a GTI; 6. Remove flares by filtering the GTI to create the finally cleaned evt2. """ import os import argparse import subprocess import shutil import logging from _context import acispy from acispy.manifest import get_manifest from acispy.pfiles import setup_pfiles from acispy.acis import ACIS from acispy.ds9 import ds9_view from acispy.header import write_keyword logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def filter_chips(infile, outfile, chips, clobber=False): """ Filter out the chips of interest, e.g., ``ccd_id=7`` for ACIS-S observation, and ``ccd_id=0:3`` for ACIS-I observation. """ chips = chips.replace("-", ":") clobber = "yes" if clobber else "no" logger.info("Filter out chips of interest: %s" % chips) logger.info("Outfile: %s" % outfile) subprocess.check_call(["punlearn", "dmcopy"]) subprocess.check_call([ "dmcopy", "infile=%s[ccd_id=%s]" % (infile, chips), "outfile=%s" % outfile, "clobber=%s" % clobber ]) logger.info("Done!\n") def detect_sources(infile, outfile, clobber=False): """ Detect (point) sources using ``celldetect``; examine the detected sources in DS9, and update the source regions and save. """ src_fits = os.path.splitext(outfile)[0] + ".fits" clobber = "yes" if clobber else "no" logger.info("Detect sources using 'celldetect' ...") logger.info("Outfile: %s" % outfile) subprocess.check_call(["punlearn", "celldetect"]) subprocess.check_call([ "celldetect", "infile=%s" % infile, "outfile=%s" % src_fits, "regfile=%s" % outfile, "clobber=%s" % clobber ]) os.remove(src_fits) shutil.copy(outfile, outfile+".orig") logger.warning("Check and update detected source regions; " + "and save/overwrite file: %s" % outfile) ds9_view(infile, regfile=outfile) logger.info("Done!\n") def remove_sources(infile, outfile, srcfile, clobber=False): """ Remove detected sources """ clobber = "yes" if clobber else "no" logger.info("Remove detected sources ...") logger.info("Outfile: %s" % outfile) subprocess.check_call(["punlearn", "dmcopy"]) subprocess.check_call([ "dmcopy", "infile=%s[exclude sky=region(%s)]" % (infile, srcfile), "outfile=%s" % outfile, "clobber=%s" % clobber ]) logger.info("Done!\n") def extract_lightcurve(infile, outfile, bintime=200, clobber=False): """ Extract the light curve from regions away from the object. """ clobber = "yes" if clobber else "no" logger.info("Extract light curve for GTI generation ...") logger.info("Outfile: %s" % outfile) regfile = os.path.splitext(outfile)[0] + ".reg" # Credit: https://stackoverflow.com/a/12654798/4856091 open(regfile, "a").close() logger.warning("Select a large region containing most of the object, " + "but also leaving enough area outside as background; " + "and save as file: %s" % regfile) ds9_view(infile) fsky = "exclude sky=region(%s)" % regfile fbintime = "bin time=::%s" % bintime subprocess.check_call(["punlearn", "dmextract"]) subprocess.check_call([ "dmextract", "infile=%s[%s][%s]" % (infile, fsky, fbintime), "outfile=%s" % outfile, "opt=ltc1", "clobber=%s" % clobber ]) logger.info("Done!\n") def make_gti(infile, outfile, scale=1.2, clobber=False): """ Examine the light curve for flares, and clip it to make the GTI. """ logger.info("Examine the light curve and create GTI ...") logger.info("Outfile: %s" % outfile) chipsfile = os.path.splitext(outfile)[0] + ".chips" if (not clobber) and (os.path.exists(outfile) or os.path.exists(chipsfile)): raise OSError("'%s' or '%s' already exists" % (outfile, chipsfile)) outimg = os.path.splitext(outfile)[0] + "_lc.jpg" lines = [ "from lightcurves import lc_clean", "lc_clean('%s')" % infile, "lc_clean('%s', scale=%s, outfile='%s')" % (infile, scale, outfile), "print_window('%s', ['format', 'jpg', 'clobber', 'True'])" % outimg ] open(chipsfile, "w").write("\n".join(lines) + "\n") subprocess.check_call(["chips", "-x", chipsfile]) if not os.path.exists(outfile): # workaround the problem that ``chips`` sometimes just failed logger.warning("*** Failed to create GTI: %s ***" % outfile) logger.warning("You need to create the GTI manually.") input("When finished GTI creation, press Enter to continue ...") logger.info("Done!\n") def filter_gti(infile, outfile, gti, clobber=False): """ Removing flares by filtering on GTI to create the finally cleaned evt2 file. """ clobber = "yes" if clobber else "no" logger.info("Filter on GTI to create cleaned evt2 file ...") logger.info("Outfile: %s" % outfile) subprocess.check_call(["punlearn", "dmcopy"]) subprocess.check_call([ "dmcopy", "infile=%s[@%s]" % (infile, gti), "outfile=%s" % outfile, "clobber=%s" % clobber ]) logger.info("Done!\n") def main(): parser = argparse.ArgumentParser( description="Make a cleaned evt2 for scientific analysis") parser.add_argument("-i", "--infile", dest="infile", help="input evt2 produced by 'chandra_repro' " + "(default: request from manifest)") parser.add_argument("-C", "--clobber", dest="clobber", action="store_true", help="overwrite existing file") args = parser.parse_args() setup_pfiles(["dmkeypar", "dmcopy", "celldetect", "dmextract"]) manifest = get_manifest() if args.infile: infile = args.infile else: infile = manifest.getpath("evt2", relative=True) chips = ACIS.get_chips_str(infile, sep="-") chips_all = ACIS.get_chips_str(infile) logger.info("infile: %s" % infile) logger.info("chips: %s" % chips) evt2_chips = "evt2_c{chips}_orig.fits".format(chips=chips) evt2_rmsrc = "evt2_c{chips}_rmsrc.fits".format(chips=chips) evt2_clean = "evt2_c{chips}_clean.fits".format(chips=chips) srcfile = "sources_celld.reg" lcfile = "ex_bkg.lc" gtifile = os.path.splitext(lcfile)[0] + ".gti" filter_chips(infile, evt2_chips, chips, clobber=args.clobber) write_keyword(evt2_chips, keyword="DETNAM", value="ACIS-{0}".format(chips_all)) detect_sources(evt2_chips, srcfile, clobber=args.clobber) remove_sources(evt2_chips, evt2_rmsrc, srcfile, clobber=args.clobber) extract_lightcurve(evt2_rmsrc, lcfile, clobber=args.clobber) make_gti(lcfile, gtifile, clobber=args.clobber) filter_gti(evt2_rmsrc, evt2_clean, gtifile, clobber=args.clobber) # Add cleaned evt2 and other products to manifest key = "evt2_clean" manifest.setpath(key, evt2_clean) logger.info("Added '%s' to manifest: %s" % (key, manifest.get(key))) key = "reg_sources" manifest.setpath(key, srcfile) logger.info("Added '%s' to manifest: %s" % (key, manifest.get(key))) key = "gti" manifest.setpath(key, gtifile) logger.info("Added '%s' to manifest: %s" % (key, manifest.get(key))) # Remove useless intermediate files os.remove(evt2_chips) os.remove(evt2_rmsrc) if __name__ == "__main__": main()