#!/usr/bin/env python ''' Updated on November 15, 2016 to modify the input list as list of events files rather than img files. Note that earlier version with list of .img files can also be used to merge the events files. ''' def print_preamble(): print "=========================================================================\n" print "\t \t Running SXT GTI Coorector and Events Merger Script \n \t \t Task: sxt_gti_corr_evt_merger_v02.py \n \t \t Version: 0.02 Release Date: 2016-06-09 \n" print "\t \t Developed By Sunil Chandra, TIFR, Mumbai, 09, June, 2016 \n" print "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" print "Description: This tool merges the events files after correcting for overlapping exposures in GTIs. It also create merged mkf and lbt files." print "Precautionary Remark:: Merging events files is always risky job so please use this script only if it is suited for." print "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" print "=========================================================================\n" def orbit_times(evt_file, orbital_gap_time = 3000.0): import numpy as np import pyfits """ Determine the orbit start and stop times from the GTI extension """ ff = pyfits.open(evt_file) try: gtihdr = ff['GTI'].header gtidata = ff['GTI'].data except: gtihdr = ff['STDGTI'].header gtidata = ff['STDGTI'].data gtistart = gtidata.field('START') gtistop = gtidata.field('STOP') orbits = [] if (len(gtistart) > 1): tdiff = gtistart[1:] - gtistop[0:-1] #print tdiff orbitmask = np.where(abs(tdiff) > orbital_gap_time) norbits = len(orbitmask[0]) + 1 #print orbitmask[0], orbitmask[0].shape, norbits iorbit_start = np.zeros(norbits, dtype=np.int) iorbit_stop = np.zeros(norbits, dtype=np.int) iorbit_start[0] = 0 iorbit_start[1:] = orbitmask[0][:] + 1 iorbit_stop[0:len(orbitmask[0])] = orbitmask[0][:] iorbit_stop[-1] = len(gtistop) - 1 # print iorbit_start # print iorbit_stop # print gtistart[iorbit_start] # print gtistop[iorbit_stop] for i in xrange(norbits): ontime = 0.0 for j in xrange(iorbit_start[i], iorbit_stop[i] + 1): ontime += (gtistop[j] - gtistart[j]) orbits.append((gtistart[iorbit_start[i]], gtistop[iorbit_stop[i]], ontime)) else: ontime = (gtistop[0] - gtistart[0]) orbits.append((gtistart[0], gtistop[0], ontime)) ff.close() return orbits #----------GTI creator---------- def make_gtifile(fname, goodtimes, debug = False): if debug: print 'Making GTI file:', fname f = open(fname, 'w') for (tstart, tstop, ontime) in goodtimes: msg = '' msg += str(tstart) msg += ' ' msg += str(tstop) if debug: print msg f.write(msg + '\n') f.close() #--------Event extractor------------- def extractor_events(infile, outfile, gtifile, debug = False): import commands filename = infile + "[PI=0:1023]" cmd = "extractor " cmd += " filename=" + filename cmd += " eventsout=" + outfile cmd += " timefile=" + gtifile cmd += " copyall=yes regionfile = NONE qdpfile = NONE fitsbinlc = NONE unbinlc = NONE phafile = NONE imgfile = NONE gtitxt = NONE adjustgti=yes gstring = NONE timeorder = no xcolf = X ycolf = Y xcolh = X ycolh = Y xfkey = TLMAX yfkey = TLMAX xhkey = TLMAX yhkey = TLMAX phamax = TLMAX specbin = 1 binh = 1 binf = 1 binlc = \"1.0000000E+00\" tcol = TIME ecol = PI ccol = NONE gcol = GRADE gti = GTI events = EVENTS timeref = \"40000.00\" wtmapb = yes wtmapfix = yes swmapx = no swmapy = no wmapver = 2 gtinam = GTI exitnow = no" if debug: print cmd (status, output) = commands.getstatusoutput(cmd) if debug: print "exit status: ", status print output return status def time_overlap_corrector(evtfile,outdir_tmp,orbital_gap_time=10,last_orbit_time=0.0,copy_flag=1,keep_log="yes",log_dir="./"): import numpy as np import tempfile, shutil, os from astropy.io import fits f=fits.open(evtfile) inpfile_Primary_hdr = f[0].header object_name = inpfile_Primary_hdr['object'] if len(object_name.split(" ")) > 1 : for j in range(len(object_name.split(" "))) : if j == 0: object_str = object_name.split(" ")[j] else : object_str += object_name.split(" ")[j] object_name = object_str f.close() if keep_log=="yes": fl_out2=open(os.path.join(log_dir,object_name+"_TimeOverlapVerificationLog.txt"),'a') #fl_out2.write("# \t \t \t raw input orbit \t \t \t \t corrected input orbit \t Overlap Duration (s) \n") #fl_out2.write("# tstart \t tstop \t ontime \t tstart \t tstop \t ontime \t \n") satorbit=evtfile.split('_')[0] print "We are looking for {} for exposure time overlap correction ".format(object_name) min_delT=10. #Minimum acceptable length of gti file... #Deciding the time slots for various orbit data... orbits = np.array(orbit_times(evtfile, orbital_gap_time=orbital_gap_time)) norbits = len(orbits) #print 'Found ' + str(norbits) + ' orbits in ' + evtfile loopcnt=0.0;timeoverlap_vector=[] #Fetching products for various orbits.... for o in range(norbits): orbit=np.array(orbits[o]) print orbit, orbit[2] if keep_log=="yes": fl_out2.write("%s \t"%orbit) #------------------------ Time Overlap Between Various orbits and obsIDs------- diffsum=orbit[2] #print (orbit[1]-orbit[0]), diffsum if int(orbit[0]) > last_orbit_time: if loopcnt==0: deltoverlap=0.0 timeoverlap_vector.append(0.00) else: if orbit[0] > met_stop_last_orbit: #print "recent orbit start time {} (MET) is greater than the stop time of previous orbit data \n So Nothing to be done......".format(orbit[0]) deltoverlap=0.00 timeoverlap_vector.append(deltoverlap) else: recentorbitstart=orbit[0] orbit[0]=met_stop_last_orbit deltoverlap=met_stop_last_orbit - recentorbitstart orbit[2]=orbit[1]-orbit[0] if orbit[2]>min_delT: timeoverlap_vector.append(deltoverlap) met_stop_last_orbit = orbit[1] loopcnt += 1 #print orbit elif orbit[0] < last_orbit_time and orbit[1] > last_orbit_time: if loopcnt==0: recentorbitstart = orbit[0] orbit[0] = last_orbit_time deltoverlap = last_orbit_time-recentorbitstart orbit[2]=orbit[1]-orbit[0] if orbit[2]>min_delT: timeoverlap_vector.append(deltoverlap) else: if orbit[0] > met_stop_last_orbit: #print "recent orbit start time {} (MET) is greater than the stop time of previous orbit data \n So Nothing to be done......".format(recentorbitstart) deltoverlap=0.0 timeoverlap_vector.append(deltoverlap) else: recentorbitstart=orbit[0] orbit[0]=met_stop_last_orbit deltoverlap=met_stop_last_orbit - recentorbitstart orbit[2]=orbit[1]-orbit[0] if orbit[2]>min_delT: timeoverlap_vector.append(deltoverlap) met_stop_last_orbit = orbit[1] loopcnt += 1 #print orbit elif orbit[0] < last_orbit_time and orbit[1] <= last_orbit_time: print "The current orbit have already covered by previous file....\n So nothing to be done" if keep_log=="yes": fl_out2.write("\t \t \t %s \t \t \t \t \t %s \n"%(" skip","skip ")) continue elif orbit[0] == last_orbit_time and orbit[1] == last_orbit_time: print "The current orbit have already covered by previous file....\n So nothing to be done" if keep_log=="yes": fl_out2.write("\t \t \t %s \t \t \t \t \t %s \n"%("skip"," skip")) continue #print (orbit[1]-orbit[0]), (diffsum-deltoverlap) tmid=(orbit[0] + orbit[1]) * 0.5 ontime=orbit[2]-deltoverlap #delete when splitting the orbits... #print "Total Time Duration {} and total live time {}".format(diffsum,ontime) #print "orbit %s : start=%s, stop=%s, ontime=%s" % \ (str(o), str(orbit[0]), str(orbit[1]), str(ontime)) # Per orbit output files stemout = 'out_V{}_sub{}'.format(satorbit,str(o)) orbevtfile = tempfile.NamedTemporaryFile(prefix='tmp', suffix='sxt_cl.evt', dir='./', delete=True) orbevtfile=orbevtfile.name orbgtifile=orbevtfile.split("sxt_cl.evt")[0]+"sxt_orb.gti" #print "orbit event file name=%s, orbit gti file name=%s" % (orbevtfile,orbgtifile) # making gtifile for every orbit if keep_log=="yes": fl_out2.write("%s \t %s \n"%(orbit,deltoverlap)) if orbit[2]>min_delT: make_gtifile(orbgtifile,[orbit],debug=False) #print "Stage 3 : extracting evt file", orbevtfile #extracting eventfiles for different orbit status = extractor_events(evtfile, orbevtfile, orbgtifile, debug=False) if copy_flag==1: #Copying Cleaned event files without time overlap #print outdir_tmp shutil.copy(orbevtfile,os.path.join(outdir_tmp,orbevtfile.split('/')[-1])) shutil.copy(orbgtifile,os.path.join(outdir_tmp,orbgtifile.split('/')[-1])) os.system('rm tmp*') if keep_log=="yes": fl_out2.close() return timeoverlap_vector, sum(timeoverlap_vector), orbit[1] #from __future__ import print_function # run fthedit to edit the header of the fits file. def run_fthedit(infile, keyword, value): import commands print ("Running fthedit...") cmd = 'fthedit ' + infile cmd += ' keyword=' + str(keyword) cmd += ' value=' + str(value) cmd += ' operation=add' print (cmd) (status, output) = commands.getstatusoutput(cmd) print ("exit status: ", status) print (output) # status = 0 return status def ftsort(infile, outfile, columns = 'TIME', unique = 'N'): import commands print ("Running ftsort...") cmd = 'ftsort infile=\'' + infile + '\'' cmd += ' outfile=\'' + outfile + '\'' cmd += ' columns=\'' + columns + '\'' cmd += ' unique=' + unique cmd += ' clobber=yes' print (cmd) (status, output) = commands.getstatusoutput(cmd) print (output) return status def remove_duplicates(infile): import tempfile import os print("Removing duplicate rows") outfile = infile + tempfile.mktemp(prefix='_tmp', suffix='', dir="") try: ftsort(infile, outfile, columns='CCDFRAME,RAWX,RAWY,PHA', unique='y') os.unlink(infile) ftsort(outfile, infile) os.unlink(outfile) except Exception as e: print (e) def merge_evtfiles(evtfilelist, outevtfile): import numpy as np import commands import os import tempfile if (len(evtfilelist) == 0) : print ("... No files to merge !") return 999 print ("Merging event files...") tmpfile = tempfile.NamedTemporaryFile(prefix='tmp', suffix='sxt', dir='./', delete=True) print ("tmpfile : " + tmpfile.name) for evtfile in evtfilelist: tmpfile.write(evtfile + '\n') tmpfile.flush() cmd = 'extractor filename=' + '@' + tmpfile.name cmd += ' eventsout=' + outevtfile cmd += ' imgfile=NONE fitsbinlc=NONE' cmd += ' xcolf=X ycolf=Y xcolh=X ycolh=Y tcol=TIME' cmd += ' phafile=NONE' cmd += ' regionfile=NONE' cmd += ' timefile=NONE' cmd += ' copyall=yes' print (cmd) (status, output) = commands.getstatusoutput(cmd) print(output) tmpfile.close() return status def RA_DEC_to_SkyXY(RA, DEC, ra0, dec0, delta_X, delta_Y, skyX0, skyY0) : #Inputs: #RA & DEC in raidans #ra0, dec0, delta_X & delta_Y in deg & deg/pixels, respectively #skyX0 & skyY0 reference pixels import numpy as np import pyfits from math import * ra0 = radians(ra0) dec0 = radians(dec0) delta_X = radians(delta_X) delta_Y = radians(delta_Y) #print ra0, dec0 phi = np.pi + atan2(sin(DEC)*cos(dec0) - cos(DEC) * sin(dec0) * cos(RA-ra0), -cos(DEC) * sin(RA-ra0)) temp = sin(DEC) * sin(dec0) + cos(DEC) * cos(dec0) * cos(RA - ra0) if temp > 1.0 : print ".....Greater than 1.0 : {}".format(temp) temp = 1.0 elif temp < -1.0 : print ".....Less than 1.0 : {}".format(temp) temp = -1.0 theta = asin(temp) x = cos(theta) * sin(phi) / sin(theta) y = -cos(theta) * cos(phi) / sin(theta) skyX = skyX0 + x/delta_X skyY = skyY0 + y/delta_Y #print x, y return skyX, skyY def run_merge_evtfiles(evtdir,outdir,outfile,rem_dup_evt_flag=1,header_edit_flag=1): import numpy as np import sys import os, pyfits import optparse import glob args=glob.glob(os.path.join(evtdir,"*_cl.evt")) if (len(args) < 1): print ("Incorrect number of arguments..") sys.exit(1) print ("Found files :") print "Total Number of Events Files being Merged : {}".format(len(args)) status = merge_evtfiles(args, outfile) if status != 0: print ("Error merging evt files") sys.exit(1) if rem_dup_evt_flag==1: print "remove possible duplicate events in different orbits" remove_duplicates(outfile) if header_edit_flag==1: # change PHA TLMIN and TLMAX keywords run_fthedit(outfile + '+1', 'TLMIN12', 0) run_fthedit(outfile + '+1', 'TLMAX12', 4095) #change PI TLMIN and TLMAX keywords run_fthedit(outfile + '+1', 'TLMIN15', 0) run_fthedit(outfile + '+1', 'TLMAX15', 1023) #os.system("rm *_out_cl.evt") return 0 #-----To merge other fits files like mkf & lbt files def merge_files(filelist, outfile, columns=None): import numpy as np import os # # columns should be specified with, seperators # e.g. 'TIME, HKTIME, CCDTEMP' import commands import os import numpy as np print "Merging files..." if (len(filelist) == 0) : print "... No files to merge !" return 999 tmpfile = 'ftmerge_inputs.txt' np.savetxt(tmpfile,filelist,fmt="%s",delimiter="\t") ''' f = open(tmpfile, 'w') for file in filelist: f.write(str(file) + '\n') f.close() ''' cmd = 'ftmerge infile=' + '@' + tmpfile cmd += ' outfile=' + outfile if columns != None: cmd += ' columns=\'' + columns + '\'' cmd += ' clobber=y' print cmd (status, output) = commands.getstatusoutput(cmd) print output try: os.remove(tmpfile) except OSError: print "Couldn't remove ", tmpfile return status # To run the merge_files() command...... def run_merge_files(args,outdir,outfile): #fname: file list name import sys import os import optparse import numpy as np if (len(args) < 1): # parser.print_help() print "Incorrect number of arguments." sys.exit(1) print "Found files :" for arg in args: print arg tmpfile = 'tmp_mkf.fits' status = merge_files(args, tmpfile) if status != 0: print "Error merging files" sys.exit(1) status = ftsort(tmpfile, outfile) if status != 0: print "Error sorting file" sys.exit(1) try: os.remove(tmpfile) except OSError: print "Couldn't remove ", tmpfile return 0 "......Running the main progam........." #----------- Main Program Starts from here.... def main(): import tempfile import glob, sys, pyfits import os, shutil, commands import numpy as np from astropy.io import fits import numpy as np import optparse print_preamble() usage = "usage: %prog [options] " parser = optparse.OptionParser(usage) parser.add_option("-l","--keep_log", dest = "keep_log", help="Write YES/NO flag for notifying the script about the time overlap logfile", default="yes") parser.add_option("-f","--filelist",dest="full_path_file_list", help="Input File List with full path of level2 cleaned events files", default="fileList") parser.add_option("-s","--sname",dest="source", help="The Source Name for output files.", default="source") parser.add_option("-d","--dup_evt_flag",dest="dup_evt_flag", help="The Flag for duplicate events removal. \n 0: NO, 1: YES.", default=0) parser.add_option("-e","--head_updt_flag",dest="head_updt_flag", help="The Flag for duplicate events removal. \n 0: NO, 1: YES.", default=0) (options, args) = parser.parse_args() keep_log,fname,source,dup_evt_flag,head_updt_flag=options.keep_log,options.full_path_file_list,options.source,options.dup_evt_flag,options.head_updt_flag print options,keep_log,fname,source, dup_evt_flag, head_updt_flag wdir=os.getcwd() print "Current Working Directory is {} ".format(wdir) #-----Iterating over list of files... count=0 #opening the file list in a loop fileIn=open(fname,'r') loopcnt=0.0 timeoverlap_vector=[];orbitinfo=[] #open a file to make a log for individual orbit data if keep_log=="yes": fl_out=open("{}_dt_orbit_information.log".format(source),'a') #Making a temporary directory for writing the events files.... tmpdir=tempfile.mkdtemp(suffix='sxt', prefix='tmp', dir=wdir) count=0 for f in fileIn: dirstr=f.rstrip() #---Breaking paths in segments... spltddirstr=dirstr.split('/') #----Determining the data directory dtdir = "/" for j in range(len(spltddirstr)-1) : dtdir = os.path.join(dtdir,spltddirstr[j]) inpfile = pyfits.open(dirstr) inpfile_Primary_hdr = inpfile[0].header inpfile_Primary_hdu = inpfile[1].data inpfile.close() if len(inpfile_Primary_hdu) < 2 : continue satorbit = inpfile_Primary_hdr['orb_num'] # Adding Zero Before the orbit number if length of string is less than 5 if len(str(satorbit)) < 5 : #print "need to add zeros" num_zeros_to_add = 5 - len(str(satorbit)) zeros = "" for j in range(num_zeros_to_add) : zeros += "0" satorbit = zeros + str(satorbit) #----Generating the string for output data directory #print dtdir #-----Changing working dir to data directory os.chdir(dtdir) #print "Working Data Directory: {}".format(dtdir) #---Image file (*.img) fls = dirstr #---Reading the fits image file using astropy.io hdulist=fits.open(fls) #-------Reading Headers of img file...... obs_id = inpfile_Primary_hdr['obs_id'] orbitid = satorbit dateobs = inpfile_Primary_hdr['date-obs'] timeobs = inpfile_Primary_hdr['time-obs'] exptime = inpfile_Primary_hdr['exposure'] mjd = inpfile_Primary_hdr['mjd-obs'] ra_pnt = inpfile_Primary_hdr['ra_pnt'] dec_pnt = inpfile_Primary_hdr['dec_pnt'] object_name = inpfile_Primary_hdr['object'] if len(object_name.split(" ")) > 1 : for j in range(len(object_name.split(" "))) : if j == 0: object_str = object_name.split(" ")[j] else : object_str += object_name.split(" ")[j] object_name = object_str orbitinfo.append(orbitid) hdulist.close() #print "orbitid=%s : timeobs=%s, exptime=%s, mjd=%s, ra=%s dec=%s" % \ # (str(orbitid), str(timeobs), str(exptime), str(mjd), str(ra_pnt), str(dec_pnt)) evtfile = spltddirstr[-1] #print evtfile if count==0: last_orbit_time=0.0 time_overlap_vec,total_overlap_period,last_orbit_time=time_overlap_corrector(evtfile, tmpdir, orbital_gap_time=500, last_orbit_time=last_orbit_time, copy_flag=1,keep_log=keep_log,log_dir=wdir) #time_overlap_corrector(evtfile,tmpdir,orbital_gap_time=500) if keep_log=="yes": if count==0: fl_out.write("#The OBS_ID : {}\n".format(obs_id)) fl_out.write("#Orbit No. \t Date-OBS \t \t \t MJD-OBS \t Exposure_Time \t Overlap_period \t RA_pnt \t Dec_pnt \n") fl_out.write("#\t \t (UTC) \t \t (s) \t (s) \t (deg) \t (deg) \n") fl_out.write(("%s \t %sT%s \t %s \t %s \t %s \t %s \t %s \n")%(str(orbitid), str(dateobs), str(timeobs), str(mjd), str(exptime), str(total_overlap_period), str(ra_pnt), str(dec_pnt))) os.chdir(wdir) count += 1 #------ Running the tool to combine the events...... evtdir=tmpdir outdir="./" outfile="{}_or{}_{}_merged_cl.evt".format(source,orbitinfo[0],orbitinfo[-1]) run_merge_evtfiles(evtdir,outdir,outfile,rem_dup_evt_flag=dup_evt_flag,header_edit_flag=head_updt_flag) #--- Working for mkf files.... #---Reading input file list... fileIn=np.loadtxt(str(fname),dtype="str") mkffileIn=[];lbtfileIn=[] for l in range(len(fileIn)): #mkffileIn.append(fileIn[l].split("AS1")[0].split("sxt")[0]) mkffileIn.append(glob.glob(os.path.join(fileIn[l].split("AS1")[0].split("sxt.")[0],"*.mkf"))) lbtfileIn.append(glob.glob(os.path.join(fileIn[l].split("AS1")[0].split("sxt.")[0],"aux","aux2","*.lbt"))) #merging the mkf and lbt files.... mkf_outfile=outfile.split("_cl")[0]+".mkf" lbt_outfile=outfile.split("_cl")[0]+".lbt" run_merge_files(mkffileIn,outdir,mkf_outfile) run_merge_files(lbtfileIn,outdir,lbt_outfile) shutil.rmtree(tmpdir) if keep_log=="yes": fl_out.close() if __name__ == "__main__": main()