def sim_evlist(flux=.1, obstime=.5, arf=None, rmf=None, extra=None, output_filename_base=None, write_pha=False, do_graphical_output=True, loglevel='INFO') : # Time it! t_1 = time.clock() # Configure logging numeric_level = getattr(logging, loglevel.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: %s' % loglevel) logging.basicConfig(level=numeric_level, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # Welcome user, print out basic information on package versions logging.info('This is {0} (pyfact v{1})'.format(os.path.split(__file__)[1], pf.__version__)) logging.info('We are running with numpy v{0}, scipy v{1}, and pyfits v{2}'.format( np.__version__, scipy.__version__, pyfits.__version__ )) #--------------------------------------------------------------------------- logging.info('Exposure: {0} h'.format(obstime)) obstime *= 3600. #observation time in seconds obj_ra, obj_dec = 0., .5 pnt_ra, pnt_dec = 0., 0. t_min = 24600. objcosdec = np.cos(obj_dec * np.pi / 180.) #--------------------------------------------------------------------------- # Read ARF, RMF, and extra file logging.info('ARF: {0}'.format(arf)) ea, ea_erange = pf.arf_to_np(pyfits.open(arf)[1]) # DEBUG #ea /= irf_data[:,4] rm, rm_erange, rm_ebounds, rm_minprob = None, ea_erange, None, None if rmf : logging.info('RMF: {0}'.format(rmf)) rm, rm_erange, rm_ebounds, rm_minprob = pf.rmf_to_np(pyfits.open(rmf)) if extra : logging.info('Extra file: {0}'.format(extra)) extraf = pyfits.open(extra) logging.info('Using effective area with 80% containment from extra file') ea = extraf['EA80'].data.field('VAL') / .8 # 100% effective area ea_erange = 10. ** np.hstack([extraf['EA80'].data.field('BIN_LO'), extraf['EA80'].data.field('BIN_HI')[-1]]) else : logging.info('Assuming energy independent 80% cut efficiency for ARF file.') ea /= .80 #--------------------------------------------------------------------------- # Signal #log_e_cen = (irf_data[:,0] + irf_data[:,1]) / 2. e_cen = 10. ** ((np.log10(ea_erange[1:]*ea_erange[:-1])) / 2.) ea_loge_step_mean = np.log10(ea_erange[1:]/ea_erange[:-1]).mean().round(4) D('ea_loge_step_mean = {0}', ea_loge_step_mean) # DEBUG #ea_s, e_cen_s = ea, e_cen # Resample effective area to increase precision if ea_loge_step_mean > .1 : elog10step = .05 logging.info('Resampling effective area in log10(EA) vs log10(E) (elog10step = {0})'.format(elog10step)) ea_spl = scipy.interpolate.UnivariateSpline(e_cen, np.log10(ea), s=0, k=1) e_cen = 10. ** np.arange(np.log10(e_cen[0]), np.log10(e_cen[-1]), step=elog10step) ea = 10. ** ea_spl(e_cen) # DEBUG plot #plt.loglog(e_cen_s, ea_s, ) #plt.loglog(e_cen, ea, '+') #plt.show() func_pl = lambda x, p: p[0] * x ** (-p[1]) flux_f = lambda x : func_pl(x, (3.45E-11 * flux, 2.63)) f_test = scipy.interpolate.UnivariateSpline(e_cen, ea * flux_f(e_cen) * 1E4, s=0, k=1) # m^2 > cm^2 log_e_steps = np.log10(rm_erange) # Calculate event numbers for the RMF bins def get_int_rate(emin, emax) : if emin < e_cen[0] or emax > e_cen[-1] : return 0. else : return f_test.integral(emin, emax) int_rate = np.array([get_int_rate(10. ** el, 10. ** eh) for (el, eh) in zip(log_e_steps[:-1], log_e_steps[1:])]) # Sanity int_rate[int_rate < 0.] = 0. # DEBUG #int_rate_s = int_rate if rmf : D('Photon rate before RM = {0}', np.sum(int_rate)) # Apply energy distribution matrix int_rate = np.dot(int_rate, rm) D('Photon rate after RM = {0}', np.sum(int_rate)) # DEBUG plots #plt.figure(1) #plt.semilogy(log_e_steps[:-1], int_rate_s, 'o', label='PRE RMF') ##plt.plot(log_e_steps[:-1], int_rate_s, 'o', label='PRE RMF') #if rmf : # plt.semilogy(np.log10(rm_ebounds[:-1]), int_rate, '+', label='POST RMF') #plt.ylim(1E-6,1.) #plt.legend() #plt.show() ##sys.exit(0) # Calculate cumulative event numbers int_all = np.sum(int_rate) int_rate = np.cumsum(int_rate) if rmf : #log_e_steps = (np.log10(rm_ebounds[1:]) + np.log10(rm_ebounds[:-1])) / 2. log_e_steps = np.log10(rm_ebounds) # Filter out low and high values to avoid spline problems at the edges istart = np.sum(int_rate == 0.) - 1 if istart < 0 : istart = 0 istop = np.sum(int_rate / int_all > 1. - 1e-4) # This value dictates the dynamic range at the high energy end D('istart = {0}, istop = {1}', istart, istop) # DEBUG plots #plt.plot(int_rate[istart:-istop] / int_all, log_e_steps[istart + 1:-istop], '+') #plt.show() # DEBUG plots #plt.hist(int_rate[istart:-istop] / int_all) #plt.show() ev_gen_f = scipy.interpolate.UnivariateSpline( int_rate[istart:-istop] / int_all, log_e_steps[istart + 1:-istop], s=0, k=1 ) ## DEBUG plot #plt.plot(np.linspace(0.,1.,100), ev_gen_f(np.linspace(0.,1.,100)), 'o') #plt.show() # Test event generator function n_a_t = 100. a_t = ev_gen_f(np.linspace(0.,1., n_a_t)) D('Test ev_gen_f, (v = 0 / #v) = {0}, (v = NaN / #v) = {1}', np.sum(a_t == 0.) / n_a_t, np.sum(np.isnan(a_t)) / n_a_t) if (np.sum(a_t == 0.) / n_a_t > 0.05) or (np.sum(np.isnan(a_t)) / n_a_t > .05) : raise Exception('Could not generate event generator function for photons. Try to decrease the upper cut-off value in the code.') # Calculate total number of photon events n_events = int_all * obstime logging.debug('Number of photons : {0}'.format(n_events)) # Generate energy event list evlist_e = ev_gen_f(np.random.rand(n_events)) # Sanity D('Number of photons with E = NaN : {0}', np.sum(np.isnan(evlist_e))) evlist_e[np.isnan(evlist_e)] = 0. ## DEBUG plot #plt.figure(1) #plt.hist(evlist_e, range=[-2.,2.], bins=20) ##plt.show() #sys.exit(0) #------------------------------------------------------ # Apply PSF # Broken power law fit function, normalized at break energy bpl = lambda p,x : np.where(x < p[0], p[1] * (x / p[0]) ** -p[2], p[1] * (x / p[0]) ** -p[3]) evlist_psf = None if extra : d = extraf['ANGRES68'].data g = scipy.interpolate.UnivariateSpline((d.field('BIN_LO') + d.field('BIN_HI')) / 2., d.field('VAL'), s=0, k=1) evlist_psf = g(evlist_e) else : psf_p1 = [1.1, 5.5E-2, .42, .19] # Fit from SubarrayE_IFAE_50hours_20101102 evlist_psf = bpl(psf_p1, 10. ** evlist_e) logging.warning('Using dummy PSF extracted from SubarrayE_IFAE_50hours_20101102') evlist_dec = obj_dec + np.random.randn(n_events) * evlist_psf evlist_ra = obj_ra + np.random.randn(n_events) * evlist_psf / objcosdec evlist_t = t_min + obstime * np.random.rand(n_events) / 86400. #--------------------------------------------------------------------------- # Background #plt.figure(1) p_rate_area, log_e_cen = None, None if extra : d = extraf['BGRATED'].data p_rate_area = d.field('VAL') log_e_cen = (d.field('BIN_LO') + d.field('BIN_HI')) / 2 #g = scipy.interpolate.UnivariateSpline((d.field('BIN_LO') + d.field('BIN_HI')) / 2., d.field('VAL'), s=0, k=1) else : logging.warning('Using dummy background rate extracted from SubarrayE_IFAE_50hours_20101102') bgrate_p1 = [9., 5.E-4, 1.44, .49] # Fit from SubarrayE_IFAE_50hours_20101102 log_e_cen = np.linspace(-1.5, 2., 35.) p_rate_area = bpl(bgrate_p1, 10. ** log_e_cen) p_rate_area[log_e_cen < -1.] = .4 # DEBUG plot plt.semilogy(log_e_cen, p_rate_area) plt.show() p_rate_total = np.sum(p_rate_area) ev_gen_f = scipy.interpolate.UnivariateSpline( np.cumsum(p_rate_area) / np.sum(p_rate_area), log_e_cen, s=0, k=1 ) cam_acc = lambda p, x: p[0] * x ** 0. * (1. + (x / p[1]) ** p[2]) ** ((0. + p[3]) / p[2]) cam_acc_par = (1.,1.7, 6., -5.5) r_steps = np.linspace(0.001, 4., 150) int_cam_acc = np.zeros(150) for i, r in enumerate(r_steps) : int_cam_acc[i] = scipy.integrate.quad(lambda x: cam_acc(cam_acc_par, x) * x * 2. * np.pi, 0., r)[0] n_events_bg = int(p_rate_total * obstime * int_cam_acc[-1]) logging.debug('Number of protons : {0}'.format(n_events_bg)) tplt_multi = 5 evlist_bg_e = ev_gen_f(np.random.rand(n_events_bg * (tplt_multi + 1))) ev_gen_f2 = scipy.interpolate.UnivariateSpline( int_cam_acc / scipy.integrate.quad(lambda x: cam_acc(cam_acc_par, x) * 2. * x * np.pi, 0., 4.)[0], r_steps, s=0, k=1 ) evlist_bg_r = ev_gen_f2(np.random.rand(n_events_bg * (tplt_multi + 1))) r_max = 4. #evlist_bg_r = np.sqrt(np.random.rand(n_events_bg * (tplt_multi + 1))) * r_max rnd = np.random.rand(n_events_bg * (1 + tplt_multi)) evlist_bg_rx = np.sqrt(rnd) * evlist_bg_r * np.where(np.random.randint(2, size=(n_events_bg * (tplt_multi + 1))) == 0, -1., 1.) evlist_bg_ry = np.sqrt(1. - rnd) * evlist_bg_r * np.where(np.random.randint(2, size=(n_events_bg * (tplt_multi + 1))) == 0, -1., 1.) #evlist_bg_sky_r = np.sqrt(np.random.rand(n_events_bg * (tplt_multi + 1))) * r_max #evlist_bg_sky_r = ev_gen_f2(np.random.rand(n_events_bg * (tplt_multi + 1))) rnd = np.random.rand(n_events_bg * (tplt_multi + 1)) evlist_bg_ra = np.sin(2. * np.pi * rnd) * evlist_bg_r / objcosdec evlist_bg_dec = np.cos(2. * np.pi * rnd) * evlist_bg_r #plt.hist(evlist_bg_rx ** 2. + evlist_bg_ry**2., bins=50) #print float(n_events_bg * (tplt_multi + 1)) / np.sum(p_rate_area) / 86400. evlist_bg_t = t_min + obstime * np.random.rand(n_events_bg * (tplt_multi + 1)) / 86400. #--------------------------------------------------------------------------- # Plots & debug plt.figure(3) objra, objdec = 0., 0. H, xedges, yedges = np.histogram2d( np.append(evlist_bg_dec, evlist_dec), np.append(evlist_bg_ra, evlist_ra), bins=[100, 100], range=[[objra - 3., objra + 3.], [objdec - 3., objdec + 3.]] ) extent = [yedges[0], yedges[-1], xedges[-1], xedges[0]] plt.imshow(H, extent=extent, interpolation='nearest') cb = plt.colorbar() cb.set_label('Number of events') plt.xlabel('RA (deg)') plt.ylabel('Dec (deg)') test_r = np.sqrt(evlist_bg_ra ** 2. + evlist_bg_dec ** 2.) logging.debug('Number of BG events in a circle of area 1 deg^2 = {0}'.format(np.sum(test_r[0:n_events_bg] < np.sqrt(1. / np.pi)))) logging.debug('Expected number of BG event per area 1 deg^2 = {0}'.format(p_rate_total * obstime)) obj_r = np.sqrt(((obj_ra - evlist_ra) / objcosdec) ** 2. + (obj_dec - evlist_dec) ** 2.) thetamax_on, thetamax_off = .1, .22 non = np.sum(obj_r < thetamax_on) + np.sum(test_r[0:n_events_bg] < thetamax_on) noff = np.sum(test_r[0:n_events_bg] < thetamax_off) alpha = thetamax_on ** 2. / thetamax_off ** 2. logging.info('N_ON = {0}, N_OFF = {1}, ALPHA = {2}, SIGN = {3}'.format( non, noff, alpha, pf.get_li_ma_sign(non, noff, alpha))) plt.figure(2) plt.hist(obj_r ** 2., bins=30) #--------------------------------------------------------------------------- # Output to file if output_filename_base: logging.info('Writing eventlist to file {0}.eventlist.fits'.format(output_filename_base)) newtable = pyfits.new_table( pyfits.ColDefs([ pyfits.Column(name='TIME', format='1E', unit='deg', array=np.append(evlist_t, evlist_bg_t)), pyfits.Column(name='RA', format='1E', unit='deg', array=np.append(evlist_ra, evlist_bg_ra)), pyfits.Column(name='DEC', format='1E', unit='deg', array=np.append( evlist_dec, evlist_bg_dec)), pyfits.Column(name='DETX', format='1E', unit='deg', array=np.append(np.zeros(n_events), evlist_bg_rx)), pyfits.Column(name='DETY', format='1E', unit='deg', array=np.append(np.ones(n_events) * .5, evlist_bg_ry)), pyfits.Column(name='ENERGY', format='1E', unit='tev', array=10. ** np.append(evlist_e,evlist_bg_e)), pyfits.Column(name='HIL_MSW', format='1E', array=np.append(np.zeros(n_events + n_events_bg), 5. * np.ones(n_events_bg * tplt_multi))), pyfits.Column(name='HIL_MSL', format='1E', array=np.append(np.zeros(n_events + n_events_bg), 5. * np.ones(n_events_bg * tplt_multi))) ]) ) #newtable = pyfits.new_table(coldefs_new) dstart = datetime.datetime(2011, 1, 1, 0, 0) # date/time of start of the first observation dstop = dstart + datetime.timedelta(seconds=obstime) # date/time of end of the last observation dbase = datetime.datetime(2011, 1, 1) hdr = newtable.header hdr.update('RA_OBJ' , obj_ra, 'Target position RA [deg]') hdr.update('DEC_OBJ', obj_dec, 'Target position dec [deg]') hdr.update('RA_PNT', pnt_ra, 'Observation position RA [deg]') hdr.update('DEC_PNT', pnt_dec, 'Observation position dec [deg]') hdr.update('EQUINOX ', 2000.0, 'Equinox of the object') hdr.update('RADECSYS', 'FK5', 'Co-ordinate frame used for equinox') hdr.update('CREATOR', 'pfsim v{0}'.format(pf.__version__) , 'Program') hdr.update('DATE', datetime.datetime.today().strftime('%Y-%m-%d'), 'FITS file creation date (yyyy-mm-dd)') hdr.update('TELESCOP', 'CTASIM', 'Instrument name') hdr.update('EXTNAME', 'EVENTS' , 'HESARC standard') hdr.update('DATE_OBS', dstart.strftime('%Y-%m-%d'), 'Obs. start date (yy-mm-dd)') hdr.update('TIME_OBS', dstart.strftime('%H:%M:%S'), 'Obs. start time (hh:mm::ss)') hdr.update('DATE_END', dstop.strftime('%Y-%m-%d'), 'Obs. stop date (yy-mm-dd)') hdr.update('TIME_END', dstop.strftime('%H:%M:%S'), 'Obs. stop time (hh:mm::ss)') hdr.update('TSTART', 0., 'Mission time of start of obs [s]') hdr.update('TSTOP', obstime, 'Mission time of end of obs [s]') hdr.update('MJDREFI', int(pf.date_to_mjd(dstart)), 'Integer part of start MJD [s] ') hdr.update('MJDREFF', pf.date_to_mjd(dstart) - int(pf.date_to_mjd(dstart)), 'Fractional part of start MJD') hdr.update('TIMEUNIT', 'days' , 'Time unit of MJD') hdr.update('TIMESYS', 'TT', 'Terrestrial Time') hdr.update('TIMEREF', 'local', '') hdr.update('TELAPSE', obstime, 'Diff of start and end times') hdr.update('ONTIME', obstime, 'Tot good time (incl deadtime)') # No deadtime assumed hdr.update('LIVETIME', obstime, 'Deadtime=ONTIME/LIVETIME') # No deadtime assumed hdr.update('DEADC', 1., 'Deadtime fraction') # No deadtime assumed hdr.update('TIMEDEL', 1., 'Time resolution') hdr.update('EUNIT', 'TeV', 'Energy unit') hdr.update('EVTVER', 'v1.0.0', 'Event-list version number') #hdr.update('', , '') # Write eventlist to file newtable.writeto('{0}.eventlist.fits'.format(output_filename_base)) if write_pha : logging.info('Writing PHA to file {0}.pha.fits'.format(output_filename_base)) # Prepare data dat, t = np.histogram(10. ** evlist_e, bins=rm_ebounds) dat = np.array(dat, dtype=float) dat_err = np.sqrt(dat) chan = np.arange(len(dat)) # Data to PHA tbhdu = pf.np_to_pha(counts=dat, stat_err=dat_err, channel=chan, exposure=obstime, obj_ra=obj_ra, obj_dec=obj_dec, quality=np.where((dat == 0), 1, 0), dstart=dstart, dstop=dstop, dbase=dbase, creator='pfsim', version=pf.__version__, telescope='CTASIM') tbhdu.header.update('ANCRFILE', os.path.basename(arf), 'Ancillary response file (ARF)') if rmf : tbhdu.header.update('RESPFILE', os.path.basename(rmf), 'Redistribution matrix file (RMF)') # Write PHA to file tbhdu.writeto('{0}.pha.fits'.format(output_filename_base)) #---------------------------------------- # Time it! t_2 = time.clock() logging.info('Execution took {0}'.format(pf.get_nice_time(t_2 - t_1))) logging.info('Thank you for choosing {0}. Have a great day!'.format(os.path.split(__file__)[1])) #---------------------------------------- if do_graphical_output: plt.show()