示例#1
0
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))
示例#2
0
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
示例#3
0
def model_errors(catmag, band, sigma=3., mode='mag', trange=[1, 1600]):
    """
    Give upper and lower expected bounds as a function of the nominal
	    magnitude of a source. Very useful for identifying outliers.

    :param catmag: Nominal AB magnitude of the source.

    :type catmag: float

    :param band: The band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param sigma: How many sigma out to set the bounds.

    :type sigma: float

    :param mode: Units in which to report bounds. Either 'cps' or 'mag'.

    :type mode: str

    :param trange: Set of integration times to compute the bounds on, in
        seconds.

    :type trange: list

    :returns: tuple -- A two-element tuple containing the lower and upper
        bounds, respectively.
	"""

    if mode != 'cps' and mode != 'mag':
        print('mode must be set to "cps" or "mag"')
        exit(0)

    x = np.arange(trange[0], trange[1])

    cnt = gt.mag2counts(catmag, band)

    ymin = (cnt * x / x) - sigma * np.sqrt(cnt * x) / x

    ymax = (cnt * x / x) + sigma * np.sqrt(cnt * x) / x

    if mode == 'mag':
        ymin = gt.counts2mag(ymin, band)
        ymax = gt.counts2mag(ymax, band)

    return ymin, ymax
示例#4
0
def model_errors(catmag, band, sigma=3., mode='mag', trange=[1, 1600]):
    """
    Give upper and lower expected bounds as a function of the nominal
	    magnitude of a source. Very useful for identifying outliers.

    :param catmag: Nominal AB magnitude of the source.

    :type catmag: float

    :param band: The band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param sigma: How many sigma out to set the bounds.

    :type sigma: float

    :param mode: Units in which to report bounds. Either 'cps' or 'mag'.

    :type mode: str

    :param trange: Set of integration times to compute the bounds on, in
        seconds.

    :type trange: list

    :returns: tuple -- A two-element tuple containing the lower and upper
        bounds, respectively.
	"""

    if mode != 'cps' and mode != 'mag':
        print('mode must be set to "cps" or "mag"')
        exit(0)

    x = np.arange(trange[0], trange[1])

    cnt = gt.mag2counts(catmag, band)

    ymin = (cnt*x/x)-sigma*np.sqrt(cnt*x)/x

    ymax = (cnt*x/x)+sigma*np.sqrt(cnt*x)/x

    if mode == 'mag':
        ymin = gt.counts2mag(ymin, band)
        ymax = gt.counts2mag(ymax, band)

    return ymin, ymax
示例#5
0
def data_errors(catmag, band, t, sigma=3., mode='mag'):
    """
    Given an array (of counts or mags), return an array of n-sigma error values.

    :param catmag: Nominal AB magnitude of the source.

    :type catmag: float

    :param t: Set of integration times to compute the bounds on, in seconds.

    :type t: list @CHASE - is this scalar or list? Also, consider trange
        instead of t to match first method?@

    :param band: The band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param sigma: How many sigma out to set the bounds.

    :type sigma: float

    :param mode: Units in which to report bounds. Either 'cps' or 'mag'.

    :type mode: str

    :returns: tuple -- A two-element tuple containing the lower and upper
        uncertainty, respectively.
    """

    if mode != 'cps' and mode != 'mag':
        print('mode must be set to "cps" or "mag"')
        exit(0)

    cnt = gt.mag2counts(catmag, band)

    ymin = (cnt * t / t) - sigma * np.sqrt(cnt * t) / t

    ymax = (cnt * t / t) + sigma * np.sqrt(cnt * t) / t

    if mode == 'mag':
        ymin = gt.counts2mag(ymin, band)
        ymax = gt.counts2mag(ymax, band)

    return ymin, ymax
示例#6
0
def data_errors(catmag, band, t, sigma=3., mode='mag'):
    """
    Given an array (of counts or mags), return an array of n-sigma error values.

    :param catmag: Nominal AB magnitude of the source.

    :type catmag: float

    :param t: Set of integration times to compute the bounds on, in seconds.

    :type t: list @CHASE - is this scalar or list? Also, consider trange
        instead of t to match first method?@

    :param band: The band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param sigma: How many sigma out to set the bounds.

    :type sigma: float

    :param mode: Units in which to report bounds. Either 'cps' or 'mag'.

    :type mode: str

    :returns: tuple -- A two-element tuple containing the lower and upper
        uncertainty, respectively.
    """

    if mode != 'cps' and mode != 'mag':
        print('mode must be set to "cps" or "mag"')
        exit(0)

    cnt = gt.mag2counts(catmag, band)

    ymin = (cnt*t/t)-sigma*np.sqrt(cnt*t)/t

    ymax = (cnt*t/t)+sigma*np.sqrt(cnt*t)/t

    if mode == 'mag':
        ymin = gt.counts2mag(ymin, band)
        ymax = gt.counts2mag(ymax, band)

    return ymin, ymax
示例#7
0
def dmag_errors(t, band, sigma=3., mode='mag', mags=np.arange(13, 24, 0.1)):
    """
    Given an exposure time, give dmag error bars at a range of magnitudes.

    :param t: Set of integration times to compute the bounds on, in seconds.

    :type t: list @CHASE - is this scalar or list? Also, consider trange
        instead of t to match first method?@

    :param band: The band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param sigma: How many sigma out to set the bounds.

    :type sigma: float

    :param mode: Units in which to report bounds. Either 'cps' or 'mag'.

    :type mode: str

    :param mags: Set of magnitudes to compute uncertainties on.

    :type mags: numpy.ndarray

    :returns: tuple -- A three-element tuple containing the magnitudes and
        their lower and upper uncertainties, respectively.
    """

    cnts = gt.mag2counts(mags, band) * t

    ymin = (cnts - sigma / np.sqrt(cnts)) / t

    ymax = (cnts + sigma / np.sqrt(cnts)) / t

    if mode == 'mag':
        ymin = mags - gt.counts2mag(ymin, band)
        ymax = mags - gt.counts2mag(ymax, band)

    return mags, ymin, ymax
示例#8
0
def dmag_errors(t, band, sigma=3., mode='mag', mags=np.arange(13, 24, 0.1)):
    """
    Given an exposure time, give dmag error bars at a range of magnitudes.

    :param t: Set of integration times to compute the bounds on, in seconds.

    :type t: list @CHASE - is this scalar or list? Also, consider trange
        instead of t to match first method?@

    :param band: The band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param sigma: How many sigma out to set the bounds.

    :type sigma: float

    :param mode: Units in which to report bounds. Either 'cps' or 'mag'.

    :type mode: str

    :param mags: Set of magnitudes to compute uncertainties on.

    :type mags: numpy.ndarray

    :returns: tuple -- A three-element tuple containing the magnitudes and
        their lower and upper uncertainties, respectively.
    """

    cnts = gt.mag2counts(mags, band)*t

    ymin = (cnts-sigma/np.sqrt(cnts))/t

    ymax = (cnts+sigma/np.sqrt(cnts))/t

    if mode == 'mag':
        ymin = mags-gt.counts2mag(ymin, band)
        ymax = mags-gt.counts2mag(ymax, band)

    return mags, ymin, ymax
示例#9
0
import gPhoton.galextools as gt

magrange = np.arange(14, 24, 1)

expt_ratio = 0.8  # Estimate of ration of effective to raw exposure time
t_raw = np.arange(1, 1600, 1)
t_eff = expt_ratio * t_raw

for sigma in [1, 3]:
    fig = plt.figure(figsize=(8 * 2, 6 * 2))
    for i, band in enumerate(['FUV', 'NUV']):
        plt.subplot(2, 1, i)
        plt.grid(b=True)
        plt.semilogx()
        plt.xlim(1, 1600)
        plt.title('{b} Detection Threshholds'.format(b=band))
        plt.xlabel('Exposure Bin Depth (s)')
        plt.ylabel('{n} Sigma Error (AB Mag)'.format(n=sigma))
        for mag in magrange:
            cps = gt.mag2counts(mag, band)
            cps_err = sigma * np.sqrt(cps * t_eff) / t_eff
            mag_err = mag - gt.counts2mag(cps + cps_err, band)
            plt.plot(t_raw, mag_err, label=mag)
        plt.legend()
    plt.savefig('GALEX {n} Sigma Detection Limits.png'.format(n=sigma))
示例#10
0
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)
示例#11
0
def inject_and_recover(
        n=1000,
        omit_incompletes=True,
        band='NUV',
        stepsz=30.,
        trange=[0, 1600],
        resolution=0.05,
        distance=2.7,  # parsecs
        quiescent_mag=18,  # approx. NUV mag
        mag_range=[13, 18],  # approx. GALEX NUV bright limit
        detection_threshold=5):
    """
    NOTE: deault for distance, quiescent_mag, and mag_range are for UV Ceti.
    'detection_threshold' is specified as a sigma value
    """

    output = pd.DataFrame({
        'energy_true': [],
        'energy_measured': [],
        'energy_measured_err': [],
        'energy_measured_w_q': [],
        'energy_measured_w_q_err': [],
        'q': [],
        'q_err': [],
        'q_true': [],
        'i_fpeak_mag': [],
        'i_tpeak': [],
        'i_fwidth': []
    })

    while len(output['energy_true']) < n:
        printed = False
        if not len(output['energy_true']) % 10000 and not printed:
            print('Injecting: {x}% done...'.format(
                x=float(len(output['energy_true'])) / float(n) * 100.))
            # Turn off counter in cases where the injected flare is rejected
            # for being truncated, so you don't get the same status update
            # printed multiple times.
            printed = True

        fpeak_mag = np.random.uniform(low=mag_range[0], high=mag_range[1])
        # Peaks within the visit
        tpeak = np.random.uniform(low=trange[0], high=trange[1])
        # FWHM in seconds
        fwidth = np.random.uniform(low=1, high=300)

        model, lc = fake_a_flare(band=band,
                                 quiescent_mag=quiescent_mag,
                                 fpeak_mag=fpeak_mag,
                                 stepsz=stepsz,
                                 trange=trange,
                                 tpeak=tpeak,
                                 fwidth=fwidth,
                                 resolution=resolution)

        # Calculate the "true" flare energy.
        model_energy = calculate_ideal_flare_energy(
            model, mag2counts(quiescent_mag, band), distance)

        # Estimate the INFF.
        q, q_err = get_inff(lc)

        # Detect flares.
        fr, quiescence, quiescence_err = refine_flare_ranges(
            lc, sigma=detection_threshold, makeplot=False)

        if not len(fr):
            output = output.append(
                pd.Series({
                    'energy_true': model_energy,
                    'energy_measured': 0,  #energy[0],
                    'energy_measured_err': 0,  #energy[1],
                    'energy_measured_w_q': 0,  #energy_w_q[0],
                    'energy_measured_w_q_err': 0,  #energy_w_q[1],
                    'q': q,
                    'q_err': q_err,
                    'q_true': quiescent_mag,
                    'i_fpeak_mag': fpeak_mag,
                    'i_tpeak': tpeak,
                    'i_fwidth': fwidth
                }),
                ignore_index=True)

        for f in fr:
            if omit_incompletes and ((f[0] == 0) or f[-1] == len(lc) - 1):
                continue

            energy = calculate_flare_energy(lc, f, distance, band=band)
            energy_w_q = calculate_flare_energy(
                lc,
                f,
                distance,
                band=band,
                quiescence=[mag2counts(quiescent_mag, band), 0.0])
            output = output.append(pd.Series({
                'energy_true':
                model_energy,
                'energy_measured':
                energy[0],
                'energy_measured_err':
                energy[1],
                'energy_measured_w_q':
                energy_w_q[0],
                'energy_measured_w_q_err':
                energy_w_q[1],
                'q':
                q,
                'q_err':
                q_err,
                'q_true':
                quiescent_mag,
                'i_fpeak_mag':
                fpeak_mag,
                'i_tpeak':
                tpeak,
                'i_fwidth':
                fwidth
            }),
                                   ignore_index=True)
            # Update counter again.
            printed = False
    return output
示例#12
0
 def test_mag2counts_NUV(self):
     self.assertAlmostEqual(gt.mag2counts(16,'NUV'),10.**(-(16-20.08)/2.5))
示例#13
0
 def test_mag2counts_FUV(self):
     self.assertAlmostEqual(gt.mag2counts(16,'FUV'),10.**(-(16-18.82)/2.5))
示例#14
0
import gPhoton.galextools as gt

magrange = np.arange(14,24,1)

expt_ratio = 0.8 # Estimate of ration of effective to raw exposure time
t_raw = np.arange(1,1600,1)
t_eff = expt_ratio*t_raw

for sigma in [1,3]:
    fig = plt.figure(figsize=(8*2,6*2))
    for i,band in enumerate(['FUV','NUV']):
        plt.subplot(2,1,i)
        plt.grid(b=True)
        plt.semilogx()
        plt.xlim(1,1600)
        plt.title('{b} Detection Threshholds'.format(b=band))
        plt.xlabel('Exposure Bin Depth (s)')
        plt.ylabel('{n} Sigma Error (AB Mag)'.format(n=sigma))
        for mag in magrange:
            cps = gt.mag2counts(mag,band)
            cps_err = sigma*np.sqrt(cps*t_eff)/t_eff
            mag_err = mag-gt.counts2mag(cps+cps_err,band)
            plt.plot(t_raw,mag_err,label=mag)
        plt.legend()
    plt.savefig('GALEX {n} Sigma Detection Limits.png'.format(n=sigma))