def calculate_flare_energy(lc, frange, distance, binsize=30, band='NUV', effective_widths={ 'NUV': 729.94, 'FUV': 255.45 }, quiescence=None): """ Calculates the energy of a flare in erg. """ if not quiescence: q, _ = get_inff(lc) # Convert to aperture-corrected flux q = gt.mag2counts( gt.counts2mag(q, band) - gt.apcorrect1(gt.aper2deg(6), band), band) else: q = quiescence[0] # Convert from parsecs to cm distance_cm = distance * 3.086e+18 if 'cps_apcorrected' in lc.keys(): # Converting from counts / sec to flux units. flare_flux = (np.array( gt.counts2flux(np.array(lc.iloc[frange]['cps_apcorrected']), band)) - gt.counts2flux(q, band)) else: # Really need to have aperture-corrected counts/sec. raise ValueError("Need aperture-corrected cps fluxes to continue.") # Zero any flux values where the flux is below the INFF so that we don't subtract from the total flux! flare_flux = np.array([0 if f < 0 else f for f in flare_flux]) flare_flux_err = gt.counts2flux(np.array(lc.iloc[frange]['cps_err']), band) tbins = (np.array(lc.iloc[frange]['t1'].values) - np.array(lc.iloc[frange]['t0'].values)) # Caluclate the area under the curve. integrated_flux = (binsize * flare_flux).sum() """ GALEX effective widths from http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?id=GALEX/GALEX.NUV width = 729.94 A http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?id=GALEX/GALEX.FUV width = 255.45 A """ # Convert integrated flux to a fluence using the GALEX effective widths. fluence = integrated_flux * effective_widths[band] fluence_err = (np.sqrt( ((gt.counts2flux(lc.iloc[frange]['cps_err'], band) * binsize)** 2).sum()) * effective_widths[band]) energy = (4 * np.pi * (distance_cm**2) * fluence) energy_err = (4 * np.pi * (distance_cm**2) * fluence_err) return energy, energy_err
def calculate_ideal_flare_energy(model, quiescence, distance, band='NUV', effective_widths={ 'NUV': 729.94, 'FUV': 255.45 }, quiet=True): """ Because it's an 'ideal flare,' we can make assumptions that improve runtime. """ q = quiescence distance_cm = distance * 3.086e+18 # convert from parsecs to cm # NOTE: This does not interpolate over small gaps. flare_flux = np.array(model['flux'].values) - counts2flux(q, band) flare_flux = np.array([0 if f < 0 else f for f in flare_flux]) tbins = np.array(model['t1']) - np.array(model['t0']) integrated_flux = (tbins * flare_flux).sum() """ GALEX effective widths from http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?id=GALEX/GALEX.NUV: 729.94 Angstroms http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?id=GALEX/GALEX.FUV: 255.45 Angstroms """ fluence = integrated_flux * effective_widths[band] energy = (4 * np.pi * (distance_cm**2) * fluence) return energy
def quickmag(band, ra0, dec0, tranges, radius, annulus=None, stepsz=None, verbose=0, detsize=1.25, coadd=False): """ Primary wrapper function for generating and synthesizing all of the parameters and calculations necessary to create light curves. :param band: The band being used, either 'FUV' or 'NUV'. :type band: str :param ra0: Right ascension, in degrees, of the target position. :type ra0: float :param dec0: Declination, in degrees, of the target position. :type dec0: float :param tranges: Set of time ranges to query within in GALEX time seconds. :type tranges: list :param radius: The radius of the photometric aperture, in degrees. :type radius: float :param annulus: Radii of the inner and outer extents of the background annulus, in degrees. :type annulus: list :param stepsz: The size of the time bins to use, in seconds. :type stepsz: float :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :param detsize: Effective diameter, in degrees, of the field-of-view. :param coadd: Set to True if calculating a total flux instead of flux from each time bin. :type coadd: bool :returns: dict -- The light curve, including input parameters. """ if verbose: mc.print_inline("Retrieving all of the target events.") searchradius = radius if annulus is None else annulus[1] data = pullphotons(band, ra0, dec0, tranges, searchradius, verbose=verbose, detsize=detsize) if not data: return None if verbose: mc.print_inline("Binning data according to requested depth.") # Multiple ways of defining bins try: trange = [np.array(tranges).min(), np.array(tranges).max()] except ValueError: trange = tranges if coadd: bins = np.array(trange) elif stepsz: bins = np.append(np.arange(trange[0], trange[1], stepsz), max(trange)) else: bins = np.unique(np.array(tranges).flatten()) lcurve = {'params':gphot_params(band, [ra0, dec0], radius, annulus=annulus, verbose=verbose, detsize=detsize, stepsz=stepsz, trange=trange)} # This is equivalent in function to np.digitize(data['t'],bins) except # that it's much, much faster. See numpy issue #2656 at # https://github.com/numpy/numpy/issues/2656 bin_ix = np.searchsorted(bins, data['t'], "right") try: lcurve['t0'] = bins[np.unique(bin_ix)-1] lcurve['t1'] = bins[np.unique(bin_ix)] lcurve['exptime'] = np.array( dbt.compute_exptime(band, tranges if coadd else list(zip( lcurve['t0'], lcurve['t1'])), verbose=verbose, coadd=coadd, detsize=detsize, skypos=[ra0, dec0])) except IndexError: if np.isnan(data['t']): if verbose: mc.print_inline( "No valid data available in {t}".format(t=tranges)) lcurve['t0'] = np.array([np.nan]) lcurve['t1'] = np.array([np.nan]) lcurve['exptime'] = np.array([0]) angSep = mc.angularSeparation(ra0, dec0, data['ra'], data['dec']) aper_ix = np.where(angSep <= radius) lcurve['t0_data'] = reduce_lcurve(bin_ix, aper_ix, data['t'], np.min) lcurve['t1_data'] = reduce_lcurve(bin_ix, aper_ix, data['t'], np.max) lcurve['t_mean'] = reduce_lcurve(bin_ix, aper_ix, data['t'], np.mean) lcurve['q_mean'] = reduce_lcurve(bin_ix, aper_ix, data['q'], np.mean) lcurve['counts'] = reduce_lcurve(bin_ix, aper_ix, data['t'], len) lcurve['flat_counts'] = reduce_lcurve(bin_ix, aper_ix, 1./data['response'], np.sum) lcurve['responses'] = reduce_lcurve(bin_ix, aper_ix, data['response'], np.mean) lcurve['detxs'] = reduce_lcurve(bin_ix, aper_ix, data['col'], np.mean) lcurve['detys'] = reduce_lcurve(bin_ix, aper_ix, data['row'], np.mean) lcurve['detrad'] = mc.distance(lcurve['detxs'], lcurve['detys'], 400, 400) lcurve['racent'] = reduce_lcurve(bin_ix, aper_ix, data['ra'], np.mean) lcurve['deccent'] = reduce_lcurve(bin_ix, aper_ix, data['dec'], np.mean) skybgmcatdata = dbt.get_mcat_data([ra0, dec0], radius) lcurve['mcat_bg'] = lcurve['exptime']*np.array( [dbt.mcat_skybg(band, [ra0, dec0], radius, trange=tr, mcat=skybgmcatdata, verbose=verbose) for tr in zip(lcurve['t0'], lcurve['t1'])]) if annulus is not None: annu_ix = np.where((angSep > annulus[0]) & (angSep <= annulus[1])) lcurve['bg_counts'] = reduce_lcurve(bin_ix, annu_ix, data['t'], len) lcurve['bg_flat_counts'] = reduce_lcurve( bin_ix, annu_ix, data['response'], np.sum) lcurve['bg'] = (mc.area(radius)*lcurve['bg_flat_counts'] / (mc.area(annulus[1])-mc.area(annulus[0]))) else: lcurve['bg_counts'] = np.zeros(len(lcurve['counts'])) lcurve['bg_flat_counts'] = np.zeros(len(lcurve['counts'])) lcurve['bg'] = np.zeros(len(lcurve['counts'])) lcurve['cps'] = lcurve['flat_counts']/lcurve['exptime'] lcurve['cps_err'] = aperture_error(lcurve['flat_counts'], lcurve['exptime']) lcurve['cps_bgsub'] = (lcurve['flat_counts']- lcurve['bg'])/lcurve['exptime'] lcurve['cps_bgsub_err'] = aperture_error( lcurve['flat_counts'], lcurve['exptime'], bgcounts=lcurve['bg']) lcurve['cps_mcatbgsub'] = (lcurve['flat_counts']- lcurve['mcat_bg'])/lcurve['exptime'] lcurve['cps_mcatbgsub_err'] = aperture_error( lcurve['flat_counts'], lcurve['exptime'], bgcounts=lcurve['mcat_bg']) lcurve['flux'] = gxt.counts2flux(lcurve['cps'], band) lcurve['flux_err'] = gxt.counts2flux(lcurve['cps_err'], band) lcurve['flux_bgsub'] = gxt.counts2flux(lcurve['cps_bgsub'], band) lcurve['flux_bgsub_err'] = gxt.counts2flux(lcurve['cps_bgsub_err'], band) lcurve['flux_mcatbgsub'] = gxt.counts2flux(lcurve['cps_mcatbgsub'], band) lcurve['flux_mcatbgsub_err'] = gxt.counts2flux( lcurve['cps_mcatbgsub_err'], band) # NOTE: These conversions to mag can throw logarithm warnings if the # background is brighter than the source, resuling in a negative cps which # then gets propagated as a magnitude of NaN. lcurve['mag'] = gxt.counts2mag(lcurve['cps'], band) lcurve['mag_err_1'] = (lcurve['mag'] - gxt.counts2mag(lcurve['cps'] + lcurve['cps_err'], band)) lcurve['mag_err_2'] = (gxt.counts2mag(lcurve['cps'] - lcurve['cps_err'], band) - lcurve['mag']) lcurve['mag_bgsub'] = gxt.counts2mag(lcurve['cps_bgsub'], band) lcurve['mag_bgsub_err_1'] = (lcurve['mag_bgsub'] - gxt.counts2mag(lcurve['cps_bgsub'] + lcurve['cps_bgsub_err'], band)) lcurve['mag_bgsub_err_2'] = (gxt.counts2mag(lcurve['cps_bgsub'] - lcurve['cps_bgsub_err'], band) - lcurve['mag_bgsub']) lcurve['mag_mcatbgsub'] = gxt.counts2mag(lcurve['cps_mcatbgsub'], band) lcurve['mag_mcatbgsub_err_1'] = (lcurve['mag_mcatbgsub'] - gxt.counts2mag(lcurve['cps_mcatbgsub'] + lcurve['cps_mcatbgsub_err'], band)) lcurve['mag_mcatbgsub_err_2'] = (gxt.counts2mag(lcurve['cps_mcatbgsub'] - lcurve['cps_mcatbgsub_err'], band) - lcurve['mag_mcatbgsub']) lcurve['photons'] = data lcurve['flags'] = getflags(band, bin_ix, lcurve, verbose=verbose) return lcurve
def fake_a_flare( band='NUV', quiescent_mag=18, fpeak_mags=[17], # peak flux of flares stepsz=30., # integration depth in seconds trange=[0, 1600], # visit length in seconds tpeaks=[250], # peak time of flares fwidths=[60], # "fwhm" of flares resolution=0.05, # normal photon time resolution flat_err=0.15 # 15% error in the NUV flat field ): quiescent_cps = mag2counts(quiescent_mag, band) t = np.arange(trange[0], trange[1], resolution) tbins = np.arange(trange[0], trange[1], stepsz) models = [] for ii, fpeak_mag, tpeak, fwidth in zip(range(len(fpeak_mags)), fpeak_mags, tpeaks, fwidths): fpeak_cps = mag2counts(fpeak_mag, band) flare = (aflare(t, [tpeak, fwidth, max(fpeak_cps - quiescent_cps, 0)]) + quiescent_cps) flare_binned = [] for t0 in tbins: ix = np.where((t >= t0) & (t < t0 + stepsz)) flare_binned += [np.array(flare)[ix].sum() / len(ix[0])] flare_binned_counts = np.array(flare_binned) * stepsz flare_obs = np.array([ np.random.normal(loc=counts, scale=np.sqrt(counts)) / stepsz for counts in flare_binned_counts ]) flare_obs_err = np.array( [np.sqrt(counts) / stepsz for counts in flare_binned_counts]) model_dict = { 't0': t, 't1': t + resolution, 'cps': flare, 'cps_err': np.zeros(len(flare)), 'flux': counts2flux(flare, band), 'flux_err': np.zeros(len(flare)), 'flags': np.zeros(len(flare)) } models.append(pd.DataFrame(model_dict)) # Construct a simulated lightcurve dataframe. # NOTE: Since we don't need to worry about aperture corrections, we # copy the cps and cps_err into those so the paper's pipeline can run on # this simulated light curve too. We assume no missing time coverage in # the time bins, since those with bad coverage are avoided in our paper's # pipeline anyways, and thus set the 'expt' to be the same as the # requested bin size. if ii == 0: # First flare in visit, setup the entire light curve. lc_dict = { 't0': tbins, 't1': tbins + stepsz, 'cps': flare_obs, 'cps_err': flare_obs_err, 'cps_apcorrected': flare_obs, 'counts': flare_binned_counts, 'flux': counts2flux(flare_obs, band), 'flux_err': counts2flux(flare_obs_err, band), 'expt': np.full(len(tbins), stepsz), 'flags': np.zeros(len(tbins)) } else: # More flares in this light curve, only need to adjust the fluxes. lc_dict['cps'] += flare_obs lc_dict['cps_err'] = ((lc_dict['cps_err'])**2. + (flare_obs_err)**2.)**0.5 lc_dict['cps_apcorrected'] += flare_obs lc_dict['counts'] += flare_binned_counts lc_dict['flux'] += counts2flux(flare_obs, band) lc_dict['flux_err'] = ((lc_dict['flux_err'])**2. + (counts2flux(flare_obs_err, band))**2.)**0.5 # "TRUTH" + simulated lightcurve dataframe return models, pd.DataFrame(lc_dict)
def test_counts2flux_NUV(self): self.assertAlmostEqual(gt.counts2flux(10,'NUV'),2.06e-16* 10)
def test_counts2flux_FUV(self): self.assertAlmostEqual(gt.counts2flux(10,'FUV'),1.4e-15 * 10)
def quickmag(band, ra0, dec0, tranges, radius, annulus=None, stepsz=None, verbose=0, detsize=1.25, coadd=False): """ Primary wrapper function for generating and synthesizing all of the parameters and calculations necessary to create light curves. :param band: The band being used, either 'FUV' or 'NUV'. :type band: str :param ra0: Right ascension, in degrees, of the target position. :type ra0: float :param dec0: Declination, in degrees, of the target position. :type dec0: float :param tranges: Set of time ranges to query within in GALEX time seconds. :type tranges: list :param radius: The radius of the photometric aperture, in degrees. :type radius: float :param annulus: Radii of the inner and outer extents of the background annulus, in degrees. :type annulus: list :param stepsz: The size of the time bins to use, in seconds. :type stepsz: float :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :param detsize: Effective diameter, in degrees, of the field-of-view. :param coadd: Set to True if calculating a total flux instead of flux from each time bin. :type coadd: bool :returns: dict -- The light curve, including input parameters. """ if verbose: mc.print_inline("Retrieving all of the target events.") searchradius = radius if annulus is None else annulus[1] data = pullphotons(band, ra0, dec0, tranges, searchradius, verbose=verbose, detsize=detsize) if not data: return None if verbose: mc.print_inline("Binning data according to requested depth.") # Multiple ways of defining bins try: trange = [np.array(tranges).min(), np.array(tranges).max()] except ValueError: trange = tranges if coadd: bins = np.array(trange) elif stepsz: bins = np.append(np.arange(trange[0], trange[1], stepsz), max(trange)) else: bins = np.unique(np.array(tranges).flatten()) lcurve = { 'params': gphot_params(band, [ra0, dec0], radius, annulus=annulus, verbose=verbose, detsize=detsize, stepsz=stepsz, trange=trange) } # This is equivalent in function to np.digitize(data['t'],bins) except # that it's much, much faster. See numpy issue #2656 at # https://github.com/numpy/numpy/issues/2656 bin_ix = np.searchsorted(bins, data['t'], "right") try: lcurve['t0'] = bins[np.unique(bin_ix) - 1] lcurve['t1'] = bins[np.unique(bin_ix)] lcurve['exptime'] = np.array( dbt.compute_exptime( band, tranges if coadd else list(zip(lcurve['t0'], lcurve['t1'])), verbose=verbose, coadd=coadd, detsize=detsize, skypos=[ra0, dec0])) except IndexError: if np.isnan(data['t']): if verbose: mc.print_inline( "No valid data available in {t}".format(t=tranges)) lcurve['t0'] = np.array([np.nan]) lcurve['t1'] = np.array([np.nan]) lcurve['exptime'] = np.array([0]) angSep = mc.angularSeparation(ra0, dec0, data['ra'], data['dec']) aper_ix = np.where(angSep <= radius) lcurve['t0_data'] = reduce_lcurve(bin_ix, aper_ix, data['t'], np.min) lcurve['t1_data'] = reduce_lcurve(bin_ix, aper_ix, data['t'], np.max) lcurve['t_mean'] = reduce_lcurve(bin_ix, aper_ix, data['t'], np.mean) lcurve['q_mean'] = reduce_lcurve(bin_ix, aper_ix, data['q'], np.mean) lcurve['counts'] = reduce_lcurve(bin_ix, aper_ix, data['t'], len) lcurve['flat_counts'] = reduce_lcurve(bin_ix, aper_ix, 1. / data['response'], np.sum) lcurve['responses'] = reduce_lcurve(bin_ix, aper_ix, data['response'], np.mean) lcurve['detxs'] = reduce_lcurve(bin_ix, aper_ix, data['col'], np.mean) lcurve['detys'] = reduce_lcurve(bin_ix, aper_ix, data['row'], np.mean) lcurve['detrad'] = mc.distance(lcurve['detxs'], lcurve['detys'], 400, 400) lcurve['racent'] = reduce_lcurve(bin_ix, aper_ix, data['ra'], np.mean) lcurve['deccent'] = reduce_lcurve(bin_ix, aper_ix, data['dec'], np.mean) skybgmcatdata = dbt.get_mcat_data([ra0, dec0], radius) lcurve['mcat_bg'] = lcurve['exptime'] * np.array([ dbt.mcat_skybg(band, [ra0, dec0], radius, trange=tr, mcat=skybgmcatdata, verbose=verbose) for tr in zip(lcurve['t0'], lcurve['t1']) ]) if annulus is not None: annu_ix = np.where((angSep > annulus[0]) & (angSep <= annulus[1])) lcurve['bg_counts'] = reduce_lcurve(bin_ix, annu_ix, data['t'], len) lcurve['bg_flat_counts'] = reduce_lcurve(bin_ix, annu_ix, data['response'], np.sum) lcurve['bg'] = (mc.area(radius) * lcurve['bg_flat_counts'] / (mc.area(annulus[1]) - mc.area(annulus[0]))) else: lcurve['bg_counts'] = np.zeros(len(lcurve['counts'])) lcurve['bg_flat_counts'] = np.zeros(len(lcurve['counts'])) lcurve['bg'] = np.zeros(len(lcurve['counts'])) lcurve['cps'] = lcurve['flat_counts'] / lcurve['exptime'] lcurve['cps_err'] = aperture_error(lcurve['flat_counts'], lcurve['exptime']) lcurve['cps_bgsub'] = (lcurve['flat_counts'] - lcurve['bg']) / lcurve['exptime'] lcurve['cps_bgsub_err'] = aperture_error(lcurve['flat_counts'], lcurve['exptime'], bgcounts=lcurve['bg']) lcurve['cps_mcatbgsub'] = (lcurve['flat_counts'] - lcurve['mcat_bg']) / lcurve['exptime'] lcurve['cps_mcatbgsub_err'] = aperture_error(lcurve['flat_counts'], lcurve['exptime'], bgcounts=lcurve['mcat_bg']) lcurve['flux'] = gxt.counts2flux(lcurve['cps'], band) lcurve['flux_err'] = gxt.counts2flux(lcurve['cps_err'], band) lcurve['flux_bgsub'] = gxt.counts2flux(lcurve['cps_bgsub'], band) lcurve['flux_bgsub_err'] = gxt.counts2flux(lcurve['cps_bgsub_err'], band) lcurve['flux_mcatbgsub'] = gxt.counts2flux(lcurve['cps_mcatbgsub'], band) lcurve['flux_mcatbgsub_err'] = gxt.counts2flux(lcurve['cps_mcatbgsub_err'], band) # NOTE: These conversions to mag can throw logarithm warnings if the # background is brighter than the source, resuling in a negative cps which # then gets propagated as a magnitude of NaN. lcurve['mag'] = gxt.counts2mag(lcurve['cps'], band) lcurve['mag_err_1'] = ( lcurve['mag'] - gxt.counts2mag(lcurve['cps'] + lcurve['cps_err'], band)) lcurve['mag_err_2'] = ( gxt.counts2mag(lcurve['cps'] - lcurve['cps_err'], band) - lcurve['mag']) lcurve['mag_bgsub'] = gxt.counts2mag(lcurve['cps_bgsub'], band) lcurve['mag_bgsub_err_1'] = ( lcurve['mag_bgsub'] - gxt.counts2mag(lcurve['cps_bgsub'] + lcurve['cps_bgsub_err'], band)) lcurve['mag_bgsub_err_2'] = ( gxt.counts2mag(lcurve['cps_bgsub'] - lcurve['cps_bgsub_err'], band) - lcurve['mag_bgsub']) lcurve['mag_mcatbgsub'] = gxt.counts2mag(lcurve['cps_mcatbgsub'], band) lcurve['mag_mcatbgsub_err_1'] = (lcurve['mag_mcatbgsub'] - gxt.counts2mag( lcurve['cps_mcatbgsub'] + lcurve['cps_mcatbgsub_err'], band)) lcurve['mag_mcatbgsub_err_2'] = (gxt.counts2mag( lcurve['cps_mcatbgsub'] - lcurve['cps_mcatbgsub_err'], band) - lcurve['mag_mcatbgsub']) lcurve['photons'] = data lcurve['flags'] = getflags(band, bin_ix, lcurve, verbose=verbose) return lcurve
def make_lightcurve(photon_file, band, stepsz=30., skypos=(24.76279, -17.94948), aper=gt.aper2deg(7), fixed_t0=False, makefile=False, quiet=False, filetag='', lc_filename=None): """ Generate a light curve of a specific target. """ if lc_filename is None: lc_filename = photon_file.replace( '.csv', '-{stepsz}s{filetag}.csv'.format(stepsz=int(stepsz), filetag=filetag)) if os.path.exists(lc_filename) and not makefile: if not quiet: print_inline(' Pre-exists, reading in file...') return pd.read_csv(lc_filename) else: if not quiet: print_inline('Generating {fn}'.format(fn=lc_filename)) events = calibrate_photons(photon_file, band) # Below is a calculation of the re-centering, if desired. skypos_recentered = recenter(events, skypos=skypos) c1 = SkyCoord(ra=skypos[0] * u.degree, dec=skypos[1] * u.degree) c2 = SkyCoord(ra=skypos_recentered[0] * u.degree, dec=skypos_recentered[1] * u.degree) if not quiet: print('Recentering aperture on [{ra}, {dec}]'.format( ra=skypos_recentered[0], dec=skypos_recentered[1])) print("Recenter shift (arcsec): " + str(c1.separation(c2).arcsec)) ix = aper_photons(events, skypos=skypos_recentered, aper=aper) if len(ix[0]) == 0: return [], [], [], [] trange = [ np.floor(np.array(events['t'])[ix].min()), np.ceil(np.array(events['t'])[ix].max()) ] if fixed_t0: # Use this to force NUV and FUV to have the same bins trange[0] = fixed_t0 expt = compute_exptime_array(np.array(events['t'].values), band, trange, stepsz, np.array(events['flags'].values)) counts, tbins, detrads = [], [], [] col, row = np.array(events['col']), np.array(events['row']) detrad = np.sqrt((col - 400)**2 + (row - 400)**2) for t0 in np.arange(trange[0], trange[1], stepsz): tix = np.where((np.array(events['t'])[ix] >= t0) & (np.array(events['t']) < t0 + stepsz)[ix] & (np.array(events['flags'], dtype='int16')[ix] == 0)) tbins += [t0] detrads += [detrad[ix][tix].mean()] if len(tix[0]) == 0: counts += [0.] else: counts += [np.array(events['response'])[ix][tix].sum()] cps = np.array(counts) / np.array(expt) cps_err = np.sqrt(counts) / np.array(expt) lc = pd.DataFrame({ 't0': tbins, 't1': list(np.array(tbins) + stepsz), 'cps': cps, 'cps_err': cps_err, 'flux': gt.counts2flux(cps, band), 'flux_err': gt.counts2flux(cps_err, band), 'counts': counts, 'expt': expt, 'detrad': detrads }) lc['cps_apcorrected'] = apcorrect_cps(lc, band, aper=aper) lc['flux_apcorrected'] = gt.counts2flux(lc['cps_apcorrected'], band) lc.to_csv(lc_filename) return lc