def detedgewarning(bin_ix, events, verbose=0, valid_detrad=0.5): """ Assigns warning flags if any of the events of interest are adjacent to the detector edge as defined by a radius of valid_detrad in degrees. :param bin_ix: Array indices designating which events are in the time bin of interest. :type bin_ix: numpy.ndarray :param events: Set of photon events to check if they are near the detector edge. :type events: dict :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :param valid_detrad: The radius, in degrees, beyond which an edge warning is raised. :type valid_detrad: float :returns: bool -- Returns True/False whether a given set of events are too close to the edge of the detector. """ ix = np.where(mc.distance(events['photons']['col'][bin_ix], events['photons']['row'][bin_ix], 400, 400)* gxt.aper2deg(4) >= valid_detrad) return True if len(ix[0]) else False
def detedgewarning(bin_ix, events, verbose=0, valid_detrad=0.5): """ Assigns warning flags if any of the events of interest are adjacent to the detector edge as defined by a radius of valid_detrad in degrees. :param bin_ix: Array indices designating which events are in the time bin of interest. :type bin_ix: numpy.ndarray :param events: Set of photon events to check if they are near the detector edge. :type events: dict :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :param valid_detrad: The radius, in degrees, beyond which an edge warning is raised. :type valid_detrad: float :returns: bool -- Returns True/False whether a given set of events are too close to the edge of the detector. """ ix = np.where( mc.distance(events['photons']['col'][bin_ix], events['photons']['row'] [bin_ix], 400, 400) * gxt.aper2deg(4) >= valid_detrad) return True if len(ix[0]) else False
def apcorrect_cps(lc, band, aper=gt.aper2deg(7)): """ Apply the aperture correction in units of linear counts-per-second. Aperture correction is linear in magnitude units, so convert the count rate into AB mag, correct it, and then convert it back. """ return (gt.mag2counts( gt.counts2mag(lc['cps'].values, band) - gt.apcorrect1(aper, band), band))
def aper_photons(photon_data, skypos=(24.76279, -17.94948), aper=gt.aper2deg(7)): """ Extract the events within the aperture. """ image = photon_data angsep = gPhoton.MCUtils.angularSeparation(skypos[0], skypos[1], np.array(image['ra']), np.array(image['dec'])) ix = np.where((angsep <= aper) & (np.isfinite(angsep)) & (np.array(image['flags'], dtype='int16') == 0)) return ix
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 recenter(events, skypos=(24.76279, -17.94948), aper=gt.aper2deg(7), n_iters=5): """Given a position on the sky, iteratively recenter on the median photon position.""" for i in np.arange(n_iters): # iterate to recenter on the star angsep = gPhoton.MCUtils.angularSeparation(skypos[0], skypos[1], np.array(events['ra']), np.array(events['dec'])) ix = np.where((angsep <= aper) & (np.isfinite(angsep)) & (np.array(events['flags'], dtype='int16') == 0)) skypos = [ np.median(np.array(events['ra'])[ix]), np.median(np.array(events['dec'])[ix]) ] return skypos
def suggest_parameters(band, skypos, verbose=0): """ Provide suggested coordinates and photometric apertures for a source given the location of known MCAT sources nearby. :param band: The band to use, either 'FUV' or 'NUV'. :type band: str :param skypos: The right ascension and declination, in degrees. :type skypos: list :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :returns: tuple -- A five-element tuple containing the suggested right ascension, declination, photometric aperture, inner annulus, and outer annulus, all in degrees. """ mcat = get_mcat_data(skypos, 0.01) ix = np.where((mcat[band]['mag'] > 0) & (mcat[band]['fwhm'] > 0)) pos, fwhm = None, None if mcat['objid'].any(): # There is a known star at the target position! pos = [mcat['ra'][ix].mean(), mcat['dec'][ix].mean()] radius = 2*mcat[band]['fwhm'][ix].mean() if verbose: print('Recentering on {pos}.'.format(pos=pos)) print('Using aperture radius of {rad} degrees.'.format(rad=fwhm)) else: # There is no known star at the target position... pos = skypos radius = aper2deg(4) annulus = [3*radius, 5*radius] return pos[0], pos[1], radius, annulus[0], annulus[1]
def suggest_parameters(band, skypos, verbose=0): """ Provide suggested coordinates and photometric apertures for a source given the location of known MCAT sources nearby. :param band: The band to use, either 'FUV' or 'NUV'. :type band: str :param skypos: The right ascension and declination, in degrees. :type skypos: list :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :returns: tuple -- A five-element tuple containing the suggested right ascension, declination, photometric aperture, inner annulus, and outer annulus, all in degrees. """ mcat = get_mcat_data(skypos, 0.01) ix = np.where((mcat[band]['mag'] > 0) & (mcat[band]['fwhm'] > 0)) pos, fwhm = None, None if mcat['objid'].any(): # There is a known star at the target position! pos = [mcat['ra'][ix].mean(), mcat['dec'][ix].mean()] radius = 2 * mcat[band]['fwhm'][ix].mean() if verbose: print('Recentering on {pos}.'.format(pos=pos)) print('Using aperture radius of {rad} degrees.'.format(rad=fwhm)) else: # There is no known star at the target position... pos = skypos radius = aper2deg(4) annulus = [3 * radius, 5 * radius] return pos[0], pos[1], radius, annulus[0], annulus[1]
def check_radius(args): """ Checks the radius value. :param args: The command-line arguments. :type args: argparse.ArgumentParser Namespace :returns: argparse.ArgumentParser Namespace -- The updated command-line arguments. """ if not (args.radius or args.suggest or args.aperradius): print("Must specify an aperture radius.") raise SystemExit if args.radius and args.aperradius: print("Must not specify both --aperture and --mcataper.") raise SystemExit if args.aperradius and not args.radius: args.radius = aper2deg(args.aperradius) return args
def datamaker(band, skypos, outfile, maglimit=20., margin=0.005, searchradius=0.1, radius=gt.aper2deg(4), annulus=[0.0083, 0.025], verbose=0): """ Generate gAperture photometry for MCAT sources within a specified region. :param band: The band to use, either 'FUV' or 'NUV'. :type band: str :param skypos: The right ascension and declination, in degrees. :type skypos: list :param outfile: Name of output file to make. :type outfile: str :param maglimit: Faint limit to use, in AB Mag. :type maglimit: float :param margin: The margin within which two sources are consider "the same," in degrees. :type margin: float :param searchradius: The radius within which to search for sources, degrees. :type searchradius: float :param radius: The size of the aperture to measure fluxes with, in degrees. :type radius: float :param annulus: The inner and outer radii of the background annulus in degrees. :type annulus: float :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int """ extant_objids = file_setup(outfile) if extant_objids == False: print('NOT RUNNING!!*!') return False uniques = dt.find_unique_sources(band, skypos[0], skypos[1], searchradius, maglimit=maglimit) if uniques is None: print('No sources at this position.') return for pos in uniques: mcat = dt.get_mcat_data(pos, margin) if not mcat: print('Nothing at {pos}.'.format(pos=pos)) continue extant_objids = file_setup(outfile) for i, objid in enumerate(mcat['objid']): if mcat[band]['ra'][i] == -99. and mcat[band]['dec'][i] == -99.: print('No {b} source'.format(b=band)) continue if objid in extant_objids: print('Already processed.') continue #exp = dt.exp_from_objid(objid) if mcat[band]['t0'][i] < 0: print('No MCAT exposure: skipping') continue print([mcat[band]['ra'][i], mcat[band]['dec'][i]]) print([mcat[band]['t0'][i], mcat[band]['t1'][i]]) data = gAperture(band, [mcat[band]['ra'][i], mcat[band]['dec'][i]], radius, annulus=annulus, verbose=verbose, coadd=True, trange=[mcat[band]['t0'][i], mcat[band]['t1'][i]], detsize=1.25) try: csv_construct = construct_row(i, band, objid, mcat, data) print(csv_construct) with open(outfile, 'a') as csvfile: spreadsheet = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) spreadsheet.writerow(csv_construct) except TypeError: continue return
def makemap(band, skypos, trange, skyrange, response=False, verbose=0, detsize=1.1): """ Generate a single image frame. :param band: The band to use, either 'FUV' or 'NUV'. :type band: str :param skypos: The right ascension and declination, in degrees. :type skypos: list :param trange: Minimum and maximum time to use, in GALEX time seconds. :type trange: list :param skyrange: RA and Dec extent of the region of interest in degrees. :type skyrange: list :param response: Apply the response correction. :type response: bool :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. :type detsize: float :returns: numpy.ndarray - The bi-dimensional histogram of ra and dec. """ imsz = gxt.deg2pix(skypos, skyrange) photons = np.array(gQuery.getArray( gQuery.skyrect(band, skypos[0], skypos[1], trange[0], trange[1], skyrange[0], skyrange[1]), verbose=verbose), dtype='float64') try: events = {'t':photons[:, 0]/tscale, 'ra':photons[:, 1], 'dec':photons[:, 2], 'xi':photons[:, 3], 'eta':photons[:, 4], 'x':photons[:, 5], 'y':photons[:, 6]} except IndexError: if verbose > 2: print('No events found at {s} +/- {r} in {t}.'.format( s=skypos, r=skyrange, t=trange)) return np.zeros(np.array(imsz, dtype='int32')) # Trim the data on detsize col, row = ct.xieta2colrow(events['xi'], events['eta'], band) ix = np.where(gxt.aper2deg(4)*mc.distance(col, row, 400, 400) <= detsize) n = len(ix[0]) m = len(col) if n == 0: return np.zeros(np.int(imsz)) for k in list(events.keys()): events[k] = events[k][ix] events = ct.hashresponse(band, events) wcs = define_wcs(skypos, skyrange) coo = list(zip(events['ra'], events['dec'])) foc = wcs.sip_pix2foc(wcs.wcs_world2pix(coo, 1), 1) weights = 1./events['response'] if response else None H, xedges, yedges = np.histogram2d(foc[:, 1]-0.5, foc[:, 0]-0.5, bins=imsz, range=([[0, imsz[0]], [0, imsz[1]]]), weights=weights) return H
def datamaker(band, skypos, outfile, maglimit=20., margin=0.005, searchradius=0.1, radius=gt.aper2deg(4), annulus=[0.0083, 0.025], verbose=0): """ Generate gAperture photometry for MCAT sources within a specified region. :param band: The band to use, either 'FUV' or 'NUV'. :type band: str :param skypos: The right ascension and declination, in degrees. :type skypos: list :param outfile: Name of output file to make. :type outfile: str :param maglimit: Faint limit to use, in AB Mag. :type maglimit: float :param margin: The margin within which two sources are consider "the same," in degrees. :type margin: float :param searchradius: The radius within which to search for sources, degrees. :type searchradius: float :param radius: The size of the aperture to measure fluxes with, in degrees. :type radius: float :param annulus: The inner and outer radii of the background annulus in degrees. :type annulus: float :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int """ extant_objids = file_setup(outfile) if extant_objids == False: print('NOT RUNNING!!*!') return False uniques = dt.find_unique_sources(band, skypos[0], skypos[1], searchradius, maglimit=maglimit) if uniques is None: print('No sources at this position.') return for pos in uniques: mcat = dt.get_mcat_data(pos, margin) if not mcat: print('Nothing at {pos}.'.format(pos=pos)) continue extant_objids = file_setup(outfile) for i, objid in enumerate(mcat['objid']): if mcat[band]['ra'][i] == -99. and mcat[band]['dec'][i] == -99.: print('No {b} source'.format(b=band)) continue if objid in extant_objids: print('Already processed.') continue #exp = dt.exp_from_objid(objid) if mcat[band]['t0'][i] < 0: print('No MCAT exposure: skipping') continue print([mcat[band]['ra'][i], mcat[band]['dec'][i]]) print([mcat[band]['t0'][i], mcat[band]['t1'][i]]) data = gAperture(band, [mcat[band]['ra'][i], mcat[band]['dec'][i]], radius, annulus=annulus, verbose=verbose, coadd=True, trange=[mcat[band]['t0'][i], mcat[band]['t1'][i]], detsize=1.25) try: csv_construct = construct_row(i, band, objid, mcat, data) print(csv_construct) with open(outfile, 'ab') as csvfile: spreadsheet = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) spreadsheet.writerow(csv_construct) except TypeError: continue return
def calrun(outfile, band, nsamples=10, seed=323, rarange=[0., 360.], decrange=[-90., 90.], exprange=[0., 5000.], maglimit=24., verbose=0, radius=gt.aper2deg(4), annulus=[0.0083, 0.025]): """ Generate a bunch of magnitudes with comparisons against MCAT values for random points on the sky within given legal ranges. Write it to a CSV. :param outfile: Name of the output file. :type outfile: str :param band: The band being used, either 'FUV' or 'NUV'. :type band: str :param nsamples: Number of random positions to sample. :type nsamples: int :param seed: The seed to use when generating the random sample. :type seed: int :param rarange: The minimum and maximum RA range to sample from. :type rarange: list :param decrange: The minimum and maximum DEC range to sample from. :type decrange: list :param exprange: The minimum and maximum exposure time to sample, in seconds. :type exprange: list :param maglimit: The faintest source to consider. :type maglimit: float :param verbose: Verbosity level, a value of 0 is minimum verbosity. :type verbose: int :param radius: Photometric aperture radius, in degrees. :type radius: float :param annulus: Inner and outer extent of background annulus, in degrees. :type annulus: list """ (ra, dec) = find_random_positions(rarange=rarange, decrange=decrange, nsamples=nsamples, seed=seed) if verbose: print('Running {n} random samples with seed of {seed}.'.format( n=nsamples, seed=seed)) print('Bounded by RA:[{r0},{r1}] and Dec:[{d0},{d1}]'.format( r0=rarange[0], r1=rarange[1], d0=decrange[0], d1=decrange[1])) print('Actual positions used will be:') print('{pos}'.format(pos=list(zip(ra, dec)))) for skypos in zip(ra, dec): expt = gFind(skypos=skypos, band=band, quiet=True)[band]['expt'] if exprange[0] <= expt <= exprange[1]: print(skypos, expt, True) datamaker(band, skypos, outfile, maglimit=maglimit, verbose=verbose, searchradius=0.01) else: print(skypos, expt, False) return
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