예제 #1
0
def write_movie(photon_file,
                band,
                tranges,
                stepsz=30,
                overwrite=False,
                pixsz=0.000416666666666667):
    """This function creates FITS cubes based on a photon event .csv file."""
    fitsfilename = photon_file.replace('.csv',
                                       '-{s}s.fits'.format(s=int(stepsz)))
    if not os.path.exists(fitsfilename) or overwrite:
        events = calibrate_photons(photon_file, band)
        for trange in tranges:
            print_inline(trange)
            image, wcs = make_image(photon_file,
                                    band,
                                    trange=trange,
                                    events=events,
                                    pixsz=pixsz)
            try:
                movie = np.append(movie, [image], axis=0)
            except:
                movie = [image]
        hdu = pyfits.PrimaryHDU(movie)
        hdulist = pyfits.HDUList([hdu])
        hdulist.writeto(fitsfilename)
예제 #2
0
def globalcount_shuttered(band, trange, verbose=0, timestamplist=False):
    """
    Global event counts over the time range, exluding shuttered periods (due to
        no non-NULL data).

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

    :type band: str

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param timestamplist: Global event time stamps.

    :type timestamplist: list

    :returns: int -- Total global counts excluding shuttered periods.
    """

    try:
        t = (timestamplist if np.array(timestamplist).any() else
             np.array(gQuery.getArray(gQuery.uniquetimes(
                 band, trange[0], trange[1], flag=True),
                                      verbose=verbose),
                      dtype='float64')[:, 0] / gQuery.tscale)
    except IndexError:  # Shutter this whole time range.
        if verbose:
            print_inline('No data in {t0},{t1}'.format(t0=trange[0],
                                                       t1=trange[1]))
        return 0

    times = np.sort(np.unique(np.append(t, trange)))
    tranges = distinct_tranges(times, maxgap=0.05)
    nonnullevents, nullevents = 0, 0

    for trange in tranges:
        nullevents += gQuery.getValue(gQuery.deadtime2(band, trange[0],
                                                       trange[1]),
                                      verbose=verbose)

        nonnullevents += gQuery.getValue(gQuery.deadtime1(
            band, trange[0], trange[1]),
                                         verbose=verbose)

    return nullevents + nonnullevents
예제 #3
0
def globalcount_shuttered(band, trange, verbose=0, timestamplist=False):
    """
    Global event counts over the time range, exluding shuttered periods (due to
        no non-NULL data).

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

    :type band: str

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param timestamplist: Global event time stamps.

    :type timestamplist: list

    :returns: int -- Total global counts excluding shuttered periods.
    """

    try:
        t = (timestamplist if np.array(timestamplist).any() else
             np.array(gQuery.getArray(gQuery.uniquetimes(band, trange[0],
                                                         trange[1], flag=True),
                                      verbose=verbose),
                      dtype='float64')[:, 0]/gQuery.tscale)
    except IndexError: # Shutter this whole time range.
        if verbose:
            print_inline('No data in {t0},{t1}'.format(t0=trange[0], t1=trange[1]))
        return 0

    times = np.sort(np.unique(np.append(t, trange)))
    tranges = distinct_tranges(times, maxgap=0.05)
    nonnullevents, nullevents = 0, 0

    for trange in tranges:
        nullevents += gQuery.getValue(
            gQuery.deadtime2(band, trange[0], trange[1]), verbose=verbose)

        nonnullevents += gQuery.getValue(gQuery.deadtime1(band, trange[0],
                                                          trange[1]),
                                         verbose=verbose)

    return nullevents+nonnullevents
예제 #4
0
def stimcount_shuttered(band, trange, verbose=0, timestamplist=False):
    """
    Returns the stim count over a time range, excluding periods that the
        detector is considered shuttered (because of no non-NULL data).

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

    :type band: str

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param timestamplist: Global detector event timestamps.

    :type timestamplist: list

    :returns: int -- Total stim counts excluding shuttered time ranges.
    """

    try:
        t = (timestamplist if np.array(timestamplist).any() else
             np.array(gQuery.getArray(gQuery.uniquetimes(band, trange[0],
                                                         trange[1]),
                                      verbose=verbose),
                      dtype='float64')[:, 0]/gQuery.tscale)
    except IndexError: # Shutter this whole time range.
        if verbose:
            print_inline('No data in {t0},{t1}'.format(t0=trange[0], t1=trange[1]))
        return 0

    times = np.sort(np.unique(np.append(t, trange)))
    tranges = distinct_tranges(times, maxgap=0.05)
    stimcount = 0

    for trange in tranges:
        stimcount += (gQuery.getValue(gQuery.stimcount(band, trange[0],
                                                       trange[1]),
                                      verbose=verbose) +
                      gQuery.getValue(gQuery.stimcount(band, trange[0],
                                                       trange[1], null=False),
                                      verbose=verbose))

    return stimcount
예제 #5
0
def stimcount_shuttered(band, trange, verbose=0, timestamplist=False):
    """
    Returns the stim count over a time range, excluding periods that the
        detector is considered shuttered (because of no non-NULL data).

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

    :type band: str

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param timestamplist: Global detector event timestamps.

    :type timestamplist: list

    :returns: int -- Total stim counts excluding shuttered time ranges.
    """

    try:
        t = (timestamplist if np.array(timestamplist).any() else np.array(
            gQuery.getArray(gQuery.uniquetimes(band, trange[0], trange[1]),
                            verbose=verbose),
            dtype='float64')[:, 0] / gQuery.tscale)
    except IndexError:  # Shutter this whole time range.
        if verbose:
            print_inline('No data in {t0},{t1}'.format(t0=trange[0],
                                                       t1=trange[1]))
        return 0

    times = np.sort(np.unique(np.append(t, trange)))
    tranges = distinct_tranges(times, maxgap=0.05)
    stimcount = 0

    for trange in tranges:
        stimcount += (gQuery.getValue(
            gQuery.stimcount(band, trange[0], trange[1]), verbose=verbose) +
                      gQuery.getValue(gQuery.stimcount(
                          band, trange[0], trange[1], null=False),
                                      verbose=verbose))

    return stimcount
예제 #6
0
def exposure(band, trange, verbose=0):
    """
    Calculate the effective exposure time in a period, in seconds, accounting
        for shutter and deadtime. Does not account for actual sky coverage of
        the telescope during the time period queried (see: compute_exptime()
        below).

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

    :type band: str

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :returns: float -- The effective exposure time, in seconds.
    """

    rawexpt = trange[1] - trange[0]

    if rawexpt == 0.:
        return 0.

    try:
        t = (np.array(gQuery.getArray(gQuery.uniquetimes(
            band, trange[0], trange[1], flag=True),
                                      verbose=verbose),
                      dtype='float64')[:, 0] / gQuery.tscale)
    except IndexError:  # Shutter this whole time range.
        if verbose:
            print_inline('No data in {t0},{t1}'.format(t0=trange[0],
                                                       t1=trange[1]))
        return 0.

    shutter = compute_shutter(band, trange, verbose=verbose, timestamplist=t)

    deadtime = empirical_deadtime(band,
                                  trange,
                                  verbose=verbose,
                                  timestamplist=t)

    return (rawexpt - shutter) * (1. - deadtime)
예제 #7
0
def exposure(band, trange, verbose=0):
    """
    Calculate the effective exposure time in a period, in seconds, accounting
        for shutter and deadtime. Does not account for actual sky coverage of
        the telescope during the time period queried (see: compute_exptime()
        below).

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

    :type band: str

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :returns: float -- The effective exposure time, in seconds.
    """

    rawexpt = trange[1]-trange[0]

    if rawexpt == 0.:
        return 0.

    try:
        t = (np.array(gQuery.getArray(
            gQuery.uniquetimes(band, trange[0], trange[1], flag=True),
            verbose=verbose), dtype='float64')[:, 0]/gQuery.tscale)
    except IndexError: # Shutter this whole time range.
        if verbose:
            print_inline('No data in {t0},{t1}'.format(t0=trange[0], t1=trange[1]))
        return 0.

    shutter = compute_shutter(band, trange, verbose=verbose, timestamplist=t)

    deadtime = empirical_deadtime(band, trange, verbose=verbose, timestamplist=t)

    return (rawexpt-shutter)*(1.-deadtime)
예제 #8
0
def mcat_skybg(band, skypos, radius, verbose=0, trange=None, mcat=None,
               searchradius=0.1):
    """
    Estimate the sky background using the MCAT 'skybg' for nearby sources.

    :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 radius: The radius in which to search for MCAT sources in degrees.

    :type radius: float

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :returns: float -- The estimated sky background in the photometric
        aperture, in counts per second.
    """
    # Search the visit-level MCAT for nearby detections.
    # Unless the MCAT data has already been handed off for detection purposes.
    if not mcat:
        mcat = get_mcat_data(skypos, searchradius)
    try:
        # Find the distance to each source.
        dist = np.array([angularSeparation(skypos[0], skypos[1], a[0], a[1])
                         for a in zip(mcat[band]['ra'], mcat[band]['dec'])])
    except TypeError:
        print_inline(
            'No {b} MCAT sources within {r} degrees of {p}'.format(
                b=band, r=searchradius, p=skypos))
        return np.nan

    # Find visits that overlap in time.
    if not trange:
        tix = (np.array(list(range(len(mcat[band]['mag']))), dtype='int32'),)
    else:
        tix = np.where(
            ((trange[0] >= mcat[band]['t0']) & (trange[0] <= mcat[band]['t1'])) |
            ((trange[1] >= mcat[band]['t0']) & (trange[1] <= mcat[band]['t1'])) |
            ((trange[0] <= mcat[band]['t0']) & (trange[1] >= mcat[band]['t1'])))

    if not len(tix[0]):
        print_inline('No concurrent {b} MCAT source nearby.'.format(b=band))
        return np.nan # Might not be the preferred behavior here.

    ix = np.where(dist[tix] == min(dist[tix]))

    skybg = mcat[band]['skybg'][tix][ix]

    # This should rarely happen, but sometimes there's a duplicate entry in
    # the visit-level MCAT.
    if len(skybg) > 1:
        # If the skybg array is all the same value, it's a duplicate.
        if np.all(skybg == skybg[0]):
            skybg = np.asarray([skybg[0]])
        else:
            skybg = np.asarray([np.median(skybg)])

    return skybg[0]*area(radius*60.*60.)
예제 #9
0
def fGetTimeRanges(band, skypos, trange=None, detsize=1.1, verbose=0,
                   maxgap=1., minexp=1., skyrange=None, maxgap_override=False,
                   minexp_override = False):
    """
    Find the contiguous time ranges within a time range at a specific location.

    :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 (in GALEX time) to consider.

    :type trange: list

    :param detsize: The effective detector diameter, in degrees.

    :type detsize: float

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param maxgap:  Maximum gap size, in seconds, for data to be considered
        contiguous.

    :type maxgap: float

    :param minexp: Minimum gap size, in seconds, for data to be considered
        contiguous.

    :type minexp: float

    :param skyrange: Values in degrees RA and Dec of a box around skypos that
        defines the extent of the region of interest.

    :type skyrange: list

    :param maxgap_override: Enables an experimental feature where maxgap
        can be less than one second.

    :type maxgap_override: bool

    :returns: numpy.ndarray -- A valid set of time ranges, accounting for
        minimum exposure lengths and maximum gaps.
	"""

    if trange is not None:
        trange_buffer = (trange[0]-1,trange[1]+1)
        times = get_valid_times(band, skypos, trange=trange_buffer,
                            detsize=detsize, verbose=verbose, skyrange=skyrange)
        if len(times):
            times = np.append(times,times[-1]+1)
            if times[0]<trange[0]:
                times[0]=trange[0]
            if times[-1]>trange[1]:
                times[-1]=trange[1]
    else:
        times = get_valid_times(band, skypos, trange=None, detsize=detsize,
                                    verbose=verbose, skyrange=skyrange)
        if len(times):
            times = np.append(times,times[-1]+1)

    if not len(times):
        return np.array([[]], dtype='float64')

    if verbose:
        print_inline('Parsing ~'+str(len(times)-1)+' seconds of raw exposure.')

    # NOTE: The minimum meaningful maxgap is 1 second.
    if maxgap < 1 and not maxgap_override:
        raise ValueError('maxgap must be >=1 second')

    tranges = distinct_tranges(times, maxgap=maxgap)

    if not minexp_override:
        ix = np.where(np.array(tranges)[:, 1]-np.array(tranges)[:, 0] >= minexp)
        tranges = np.array(tranges)[ix].tolist()

    return np.array(tranges, dtype='float64')
예제 #10
0
def photonpipe(outbase,
               band,
               raw6file=None,
               scstfile=None,
               aspfile=None,
               ssdfile=None,
               nullfile=None,
               verbose=0,
               retries=20,
               eclipse=None):
    """
    Apply static and sky calibrations to -raw6 GALEX data, producing fully
        aspect-corrected and time-tagged photon list files.

    :param raw6file: Name of the raw6 file to use.

    :type raw6file: str

    :param scstfile: Spacecraft state file to use.

    :type scstfile: str

    :param band: Name of the band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param outbase: Base of the output file names.

    :type outbase: str

    :param aspfile: Name of aspect file to use.

    :type aspfile: int

    :param ssdfile: Name of Stim Separation Data file to use.

    :type ssdfile: int

    :param nullfile: Name of output file to record NULL lines.

    :type nullfile: int

    :param verbose: Note used. Included for consistency with other tools.

    :type verbose: int

    :param retries: Number of query retries to attempt before giving up.

    :type retries: int
    """

    startt = time.time()

    # Scale factor for the time column in the output csv so that it
    # can be recorded as an int in the database.
    dbscale = 1000

    # This number determines the size of the chunks that gPhoton reads
    # in from the raw6 for processing. Even if your machine has a lot
    # of memory, making this number bigger is unlikely to improve the
    # processing time much because so much is eaten up by the .csv write.
    chunksz = 1000000

    # These are just constants for the mission.
    detsize = 1.25  # Detector size in degrees
    pltscl = 68.754932  # Plate scale
    aspum = pltscl / 1000.0
    arcsecperpixel = 1.5
    xi_xsc, xi_ysc, eta_xsc, eta_ysc = 0., 1., 1., 0.

    # Determine the eclipse number from the raw6 header.
    if not raw6file:
        if not eclipse:
            raise ValueError('Must specifiy eclipse if no raw6file.')
        else:
            raw6file = download_data(eclipse,
                                     band,
                                     'raw6',
                                     datadir=os.path.dirname(outbase))
            if raw6file == None:
                print('Unable to retrieve raw6 file for this eclipse.')
                return
    hdulist = pyfits.open(raw6file)
    hdr = hdulist[0].header
    hdulist.close()
    if eclipse and (eclipse != hdr['eclipse']):  # just a consistency check
        print("Warning: eclipse mismatch {e0} vs. {e1} (header)".format(
            e0=eclipse, e1=hdr['eclipse']))
    eclipse = hdr['eclipse']
    print("Processing eclipse " + str(eclipse) + ".")

    # Returns detector constants.
    print("Band is " + band + ".")
    (xclk, yclk, xcen, ycen, xscl, yscl, xslp,
     yslp) = clk_cen_scl_slp(band, eclipse)

    # This determines the values for the post-CSP detector stim scaling
    # and detector constant corrections.
    Mx, Bx, My, By, stimsep = 1, 0, 1, 0, 0
    if eclipse > 37460:
        (Mx, Bx, My, By, stimsep,
         yactbl) = compute_stimstats(raw6file, band, eclipse)
        wig2, wig2data, wlk2, wlk2data, clk2, clk2data = post_csp_caldata()

    print("Loading wiggle files...")
    wiggle_x, _ = cal.wiggle(band, 'x')
    wiggle_y, _ = cal.wiggle(band, 'y')

    print("Loading walk files...")
    walk_x, _ = cal.walk(band, 'x')
    walk_y, _ = cal.walk(band, 'y')

    print("Loading linearity files...")
    linearity_x, _ = cal.linearity(band, 'x')
    linearity_y, _ = cal.linearity(band, 'y')

    # This is for the post-CSP stim distortion corrections.
    print("Loading distortion files...")
    if eclipse > 37460:
        print(" Using stim separation of :" + str(stimsep))
    distortion_x, disthead = cal.distortion(band, 'x', eclipse, stimsep)
    distortion_y, _ = cal.distortion(band, 'y', eclipse, stimsep)
    (cube_x0, cube_dx, cube_y0, cube_dy, cube_d0, cube_dd, cube_nd, cube_nc,
     cube_nr) = (disthead['DC_X0'], disthead['DC_DX'], disthead['DC_Y0'],
                 disthead['DC_DY'], disthead['DC_D0'], disthead['DC_DD'],
                 disthead['NAXIS3'], disthead['NAXIS1'], disthead['NAXIS2'])

    if band == 'FUV':
        if not scstfile:
            if not eclipse:
                raise ValueError('Must specifiy eclipse if no scstfile.')
            else:
                scstfile = download_data(eclipse,
                                         band,
                                         'scst',
                                         datadir=os.path.dirname(outbase))
            if scstfile == None:
                print('Unable to retrieve SCST file for this eclipse.')
                return
        xoffset, yoffset = find_fuv_offset(scstfile)
    else:
        xoffset, yoffset = 0., 0.

    if os.path.isfile(str(ssdfile)):
        print("SSD file provided: " + str(ssdfile))
        stim_coef0, stim_coef1 = get_stim_coefs(ssdfile)
    elif ssdfile:
        print("SSD file requested: " + str(ssdfile))
        stim_coef0, stim_coef1 = create_ssd(raw6file, band, eclipse, ssdfile)
    else:
        print("No SSD file provided or requested.")
        stim_coef0, stim_coef1 = create_ssd(raw6file, band, eclipse)
    print("		stim_coef0, stim_coef1 = " + str(stim_coef0) + ", " +
          str(stim_coef1))

    print("Loading mask file...")
    mask, maskinfo = cal.mask(band)
    npixx = mask.shape[0]
    npixy = mask.shape[1]
    pixsz = maskinfo['CDELT2']
    maskfill = detsize / (npixx * pixsz)

    print("Loading aspect data...")
    if aspfile:
        (aspra, aspdec, asptwist, asptime, aspheader,
         aspflags) = load_aspect(aspfile)
    else:
        (aspra, aspdec, asptwist, asptime, aspheader,
         aspflags) = web_query_aspect(eclipse, retries=retries)

    minasp, maxasp = min(asptime), max(asptime)
    trange = [minasp, maxasp]
    print("			trange= ( {t0} , {t1} )".format(t0=trange[0], t1=trange[1]))
    ra0, dec0, roll0 = aspheader['RA'], aspheader['DEC'], aspheader['ROLL']
    print("			[avgRA, avgDEC, avgROLL] = [{RA}, {DEC}, {ROLL}]".format(
        RA=aspra.mean(), DEC=aspdec.mean(), ROLL=asptwist.mean()))

    # This projects the aspect solutions onto the MPS field centers.
    print("Computing aspect vectors...")
    (xi_vec, eta_vec) = gnomfwd_simple(aspra, aspdec, ra0, dec0, -asptwist,
                                       1.0 / 36000.0, 0.)

    print("Loading raw6 file...")
    raw6hdulist = pyfits.open(raw6file, memmap=1)
    raw6htab = raw6hdulist[1].header
    nphots = raw6htab['NAXIS2']
    print("		" + str(nphots) + " events")
    cnt = 0

    outfile = outbase + '.csv'
    print("Preparing output file " + outfile)
    spreadsheet = csv.writer(open(outfile, 'w'),
                             delimiter=',',
                             quotechar='|',
                             quoting=csv.QUOTE_MINIMAL)

    # If specified, dump lines with NULLS into a separate csv file.
    if nullfile:
        nullfile = outbase + '_NULL.csv'
        print("Preparing output file " + nullfile)
        NULLspreadsheet = csv.writer(open(nullfile, 'w'),
                                     delimiter=',',
                                     quotechar='|',
                                     quoting=csv.QUOTE_MINIMAL)

    print("")

    for i in range(int(nphots / chunksz) + 1):
        a = time.time()

        csvrows = []
        chunkbeg, chunkend = i * chunksz, (i + 1) * chunksz
        if chunkend > nphots:
            chunkend = nphots

        chunkid = " " + str(i + 1) + " of " + str(int(nphots / chunksz) +
                                                  1) + ": "
        print_inline(chunkid + "Unpacking raw6 data...")
        t = np.array(raw6hdulist[1].data.field('t')[chunkbeg:chunkend])
        phb1 = np.array(raw6hdulist[1].data.field('phb1')[chunkbeg:chunkend],
                        dtype='int64')
        phb2 = np.array(raw6hdulist[1].data.field('phb2')[chunkbeg:chunkend],
                        dtype='int64')
        phb3 = np.array(raw6hdulist[1].data.field('phb3')[chunkbeg:chunkend],
                        dtype='int64')
        phb4 = np.array(raw6hdulist[1].data.field('phb4')[chunkbeg:chunkend],
                        dtype='int64')
        phb5 = np.array(raw6hdulist[1].data.field('phb5')[chunkbeg:chunkend],
                        dtype='int64')

        # Bitwise "decoding" of the raw6 telemetry.
        q = ((phb4 & 3) << 3) + ((phb5 & 224) >> 5)
        xb = phb1 >> 5
        xamc = (np.array(((phb1 & 31) << 7), dtype='int16') + np.array(
            ((phb2 & 254) >> 1), dtype='int16') - np.array(
                ((phb1 & 16) << 8), dtype='int16'))
        yb = ((phb2 & 1) << 2) + ((phb3 & 192) >> 6)
        yamc = (np.array(((phb3 & 63) << 6), dtype='int16') + np.array(
            ((phb4 & 252) >> 2), dtype='int16') - np.array(
                ((phb3 & 32) << 7), dtype='int16'))
        xa = ((phb5 & 16) >> 4) + ((phb5 & 3) << 3) + ((phb5 & 12) >> 1)
        xraw0 = xb * xclk + xamc
        yraw0 = yb * yclk + yamc
        ya = np.array(
            ((((yraw0 / (2 * yclk) - xraw0 / (2 * xclk)) + 10) * 32) + xa),
            dtype='int64') % 32
        xraw = xraw0 + np.array((((xa + 7) % 32) - 16), dtype='int64') * xslp
        yraw = yraw0 + np.array((((ya + 7) % 32) - 16), dtype='int64') * yslp

        # Centering and scaling.
        x = (xraw - xcen) * xscl
        y = (yraw - ycen) * yscl

        # Post-CSP 'yac' corrections.
        if eclipse > 37460:
            x = Mx * x + Bx
            y = My * y + By
            yac = rtaph_yac(yactbl, ya, yb, yamc, eclipse)
            y = y - yac
            yac = rtaph_yac2(q, xb, yb, ya, y, aspum, wig2, wig2data, wlk2,
                             wlk2data, clk2, clk2data)
            y = y + yac

        # [Future] This and other ugly lines like it below are for the purpose
        # of memory management. There is likely a more Pythonic way.
        (phb1, phb2, phb3, phb4, phb5, xb, xamc, yb, yamc, xraw0, yraw0, xraw,
         yraw) = ([], [], [], [], [], [], [], [], [], [], [], [], [])

        flags = np.zeros(len(t))

        print_inline(chunkid + "Applying wiggle correction...")
        x_as = x * aspum
        y_as = y * aspum
        fptrx = x_as / 10. + 240.
        fptry = y_as / 10. + 240.

        x_as, y_as = [], []

        # This and other lines like it below are to verify that the
        # event is still on the detector.
        cut = ((fptrx > 0.) & (fptrx < 479.) & (fptry > 0.) & (fptry < 479.) &
               (flags == 0))
        flags[np.where(cut == False)[0]] = 8
        ix = np.where(cut == True)[0]

        blt = fptrx - np.array(fptrx, dtype='int64')
        blu = fptry - np.array(fptry, dtype='int64')
        wigx, wigy = np.zeros(len(t)), np.zeros(len(t))
        wigx[ix] = (
            (1 - blt[ix]) *
            (wiggle_x[xa[ix], np.array(fptrx[ix], dtype='int64')]) +
            (blt[ix]) *
            (wiggle_x[xa[ix], np.array(fptrx[ix], dtype='int64') + 1]))
        wigy[ix] = (
            (1 - blu[ix]) *
            (wiggle_y[ya[ix], np.array(fptry[ix], dtype='int64')]) +
            (blu[ix]) *
            (wiggle_y[ya[ix], np.array(fptry[ix], dtype='int64') + 1]))

        xdig = x + wigx / (10. * aspum)
        ydig = y + wigy / (10. * aspum)

        wigx, wigy = [], []

        print_inline(chunkid + "Applying walk correction...")
        xdig_as = xdig * aspum
        ydig_as = ydig * aspum
        fptrx = xdig_as / 10. + 240.
        fptry = ydig_as / 10. + 240.

        xdig_as, ydig_as = [], []

        cut = ((fptrx > 0.) & (fptrx < 479.) & (fptry > 0.) & (fptry < 479.) &
               (flags == 0))
        flags[np.where(cut == False)[0]] = 9
        ix = np.where(cut == True)[0]

        cut[ix] = ((walk_x[q[ix],
                           np.array(fptry[ix], dtype='int64'),
                           np.array(fptrx[ix], dtype='int64')] != -999) |
                   (walk_x[q[ix],
                           np.array(fptry[ix], dtype='int64'),
                           np.array(fptrx[ix], dtype='int64') + 1] != -999) |
                   (walk_x[q[ix],
                           np.array(fptry[ix], dtype='int64') + 1,
                           np.array(fptrx[ix], dtype='int64')] != -999) |
                   (walk_x[q[ix],
                           np.array(fptry[ix], dtype='int64') + 1,
                           np.array(fptrx[ix], dtype='int64') + 1] != -999) |
                   (walk_y[q[ix],
                           np.array(fptry[ix], dtype='int64'),
                           np.array(fptrx[ix], dtype='int64')] != -999) |
                   (walk_y[q[ix],
                           np.array(fptry[ix], dtype='int64'),
                           np.array(fptrx[ix], dtype='int64') + 1] != -999) |
                   (walk_y[q[ix],
                           np.array(fptry[ix], dtype='int64') + 1,
                           np.array(fptrx[ix], dtype='int64')] != -999) |
                   (walk_y[q[ix],
                           np.array(fptry[ix], dtype='int64') + 1,
                           np.array(fptrx[ix], dtype='int64') + 1] != -999))
        flags[np.where(cut == False)[0]] = 9
        ix = np.where(cut == True)[0]

        blt = fptrx - np.array(fptrx, dtype='int64')
        blu = fptry - np.array(fptry, dtype='int64')
        walkx, walky = np.zeros(len(t)), np.zeros(len(t))
        walkx[ix] = ((1 - blt[ix]) * (1 - blu[ix]) *
                     (walk_x[q[ix],
                             np.array(fptry[ix], dtype='int64'),
                             np.array(fptrx[ix], dtype='int64')]) + (blt[ix]) *
                     (1 - blu[ix]) *
                     (walk_x[q[ix],
                             np.array(fptry[ix], dtype='int64'),
                             np.array(fptrx[ix], dtype='int64') + 1]) +
                     (1 - blt[ix]) * (blu[ix]) *
                     (walk_x[q[ix],
                             np.array(fptry[ix], dtype='int64') + 1,
                             np.array(fptrx[ix], dtype='int64')]) + (blt[ix]) *
                     (blu[ix]) *
                     (walk_x[q[ix],
                             np.array(fptry[ix], dtype='int64') + 1,
                             np.array(fptrx[ix], dtype='int64') + 1]))
        walky[ix] = ((1 - blt[ix]) * (1 - blu[ix]) *
                     (walk_y[q[ix],
                             np.array(fptry[ix], dtype='int64'),
                             np.array(fptrx[ix], dtype='int64')]) + (blt[ix]) *
                     (1 - blu[ix]) *
                     (walk_y[q[ix],
                             np.array(fptry[ix], dtype='int64'),
                             np.array(fptrx[ix], dtype='int64') + 1]) +
                     (1 - blt[ix]) * (blu[ix]) *
                     (walk_y[q[ix],
                             np.array(fptry[ix], dtype='int64') + 1,
                             np.array(fptrx[ix], dtype='int64')]) + (blt[ix]) *
                     (blu[ix]) *
                     (walk_y[q[ix],
                             np.array(fptry[ix], dtype='int64') + 1,
                             np.array(fptrx[ix], dtype='int64') + 1]))

        print_inline(chunkid + "Applying spatial non-linearity correction...")
        xp = xdig - walkx
        yp = ydig - walky
        xp_as = xp * aspum
        yp_as = yp * aspum
        fptrx = xp_as / 10. + 240.
        fptry = yp_as / 10. + 240.

        xp, yp = [], []
        walkx, walky = [], []

        cut = ((fptrx > 0.) & (fptrx < 479.) & (fptry > 0.) & (fptry < 479.) &
               (flags == 0))
        flags[np.where(cut == False)[0]] = 10
        ix = np.where(cut == True)[0]

        blt = fptrx - np.array(fptrx, dtype='int64')
        blu = fptry - np.array(fptry, dtype='int64')

        dx, dy = np.zeros(len(t)), np.zeros(len(t))
        dx[ix] = (
            (1 - blt[ix]) *
            (1 - blu[ix]) * linearity_x[np.array(fptry[ix], dtype='int64'),
                                        np.array(fptrx[ix], dtype='int64')] +
            (blt[ix]) *
            (1 - blu[ix]) * linearity_x[np.array(fptry[ix], dtype='int64'),
                                        np.array(fptrx[ix], dtype='int64') + 1]
            + (1 - blt[ix]) *
            (blu[ix]) * linearity_x[np.array(fptry[ix], dtype='int64') + 1,
                                    np.array(fptrx[ix], dtype='int64')] +
            (blt[ix]) *
            (blu[ix]) * linearity_x[np.array(fptry[ix], dtype='int64') + 1,
                                    np.array(fptrx[ix], dtype='int64') + 1])
        dy[ix] = (
            (1 - blt[ix]) *
            (1 - blu[ix]) * linearity_y[np.array(fptry[ix], dtype='int64'),
                                        np.array(fptrx[ix], dtype='int64')] +
            (blt[ix]) *
            (1 - blu[ix]) * linearity_y[np.array(fptry[ix], dtype='int64'),
                                        np.array(fptrx[ix], dtype='int64') + 1]
            + (1 - blt[ix]) *
            (blu[ix]) * linearity_y[np.array(fptry[ix], dtype='int64') + 1,
                                    np.array(fptrx[ix], dtype='int64')] +
            (blt[ix]) *
            (blu[ix]) * linearity_y[np.array(fptry[ix], dtype='int64') + 1,
                                    np.array(fptrx[ix], dtype='int64') + 1])

        print_inline(chunkid + "Applying stim distortion correction...")

        ss = stim_coef0 + (t * stim_coef1)  # stim separation
        col, row, depth = np.zeros(len(t)), np.zeros(len(t)), np.zeros(len(t))
        col[ix] = (xp_as[ix] - cube_x0) / cube_dx
        row[ix] = (yp_as[ix] - cube_y0) / cube_dy
        depth[ix] = (ss[ix] - cube_d0) / cube_dd

        # [Future]: This throws an error sometimes like the following, may need
        # fixing...
        """PhotonPipe.py:262: RuntimeWarning: invalid value encountered in
        less depth[((depth < 0)).nonzero()[0]] = 0.
        PhotonPipe.py:263: RuntimeWarning: invalid value encountered in
        greater_equal depth[((depth >= cube_nd)).nonzero()[0]] = -1.
        ERROR: IndexError: index -9223372036854775808 is out of bounds for
        axis 0 with size 17 [PhotonPipe]
        depth[((depth < 0)).nonzero()[0]] = 0.
        depth[((depth >= cube_nd)).nonzero()[0]] = -1.
        """

        cut = ((col > -1) & (col < cube_nc) & (row > -1) & (row < cube_nr) &
               (flags == 0) & (np.array(depth, dtype='int64') < 18))
        flags[np.where(cut == False)[0]] = 11
        ix = np.where(cut == True)[0]

        xshift, yshift = np.zeros(len(t)), np.zeros(len(t))
        xshift[ix] = distortion_x[np.array(depth[ix], dtype='int64'),
                                  np.array(row[ix], dtype='int64'),
                                  np.array(col[ix], dtype='int64')]
        yshift[ix] = distortion_y[np.array(depth[ix], dtype='int64'),
                                  np.array(row[ix], dtype='int64'),
                                  np.array(col[ix], dtype='int64')]

        xshift = (xshift * arcsecperpixel) + xoffset
        yshift = (yshift * arcsecperpixel) + yoffset

        print_inline(chunkid + "Applying hotspot mask...")

        # The detectors aren't oriented the same way.
        flip = 1.
        if band == 'FUV':
            flip = -1.

        xi = (xi_xsc * (flip * (yp_as + dy + yshift) * 10.) + xi_ysc *
              (flip * (xp_as + dx + xshift) * 10.))
        eta = (eta_xsc * (flip * (yp_as + dy + yshift) * 10.) + eta_ysc *
               (flip * (xp_as + dx + xshift) * 10.))

        xp_as, yp_as, depth, ss = [], [], [], []
        dx, dy, xshift, yshift = [], [], [], []

        col = (((xi / 36000.) / (detsize / 2.) * maskfill + 1.) / 2. * npixx)
        row = (((eta / 36000.) / (detsize / 2.) * maskfill + 1.) / 2. * npixy)

        # This mask out data that is not on the detector at all
        cut = ((col > 0.) & (col < 799.) & (row > 0.) & (row < 799.) &
               (flags == 0))
        flags[np.where(cut == False)[0]] = 6
        ix = np.where(cut == True)[0]

        # This masks out hotspot regions and is experimentally deprecated.
        #cut[ix] = (
        #    (mask[np.array(col[ix], dtype='int64'),
        #          np.array(row[ix], dtype='int64')] == 1.))
        #flags[np.where(cut == False)[0]] = 6
        #ix = np.where(cut == True)[0]

        col, row = [], []

        # This gives the index of the aspect time that comes _before_
        # each photon time. Without the '-1' it will give the index
        # of the aspect time _after_ the photon time.
        print_inline(chunkid + "Mapping photon times to aspect times...")
        aspix = np.digitize(t, asptime) - 1

        print_inline(chunkid + "Applying dither correction...")
        # Use only photons that are bracketed by valid aspect solutions
        # and have been not themselves been flagged as invalid.
        cut = ((aspix > 0) & (aspix < (len(asptime) - 1)) & ((flags == 0) |
                                                             (flags == 6)))
        flags[np.where(cut == False)[0]] = 7
        ix = np.where(cut == True)[0]

        print_inline(chunkid + "Interpolating aspect solutions...")
        dxi, deta = np.zeros(len(t)), np.zeros(len(t))
        dxi[ix] = ((xi_vec[aspix[ix] + 1] - xi_vec[aspix[ix]]) *
                   (t[ix] - asptime[aspix[ix]]) /
                   (asptime[aspix[ix] + 1] - asptime[aspix[ix]]))
        deta[ix] = ((eta_vec[aspix[ix] + 1] - eta_vec[aspix[ix]]) *
                    (t[ix] - asptime[aspix[ix]]) /
                    (asptime[aspix[ix] + 1] - asptime[aspix[ix]]))

        print_inline(chunkid + "Mapping to sky...")
        ra, dec = np.zeros(len(t)), np.zeros(len(t))
        ra[ix], dec[ix] = gnomrev_simple(xi[ix] + dxi[ix], eta[ix] + deta[ix],
                                         aspra[aspix[ix]], aspdec[aspix[ix]],
                                         -asptwist[aspix[ix]], 1 / 36000., 0.)

        cut = (((asptime[aspix[ix] + 1] - asptime[aspix[ix]]) == 1) &
               (aspflags[aspix[ix]] % 2 == 0) &
               (aspflags[aspix[ix] + 1] % 2 == 0) &
               (aspflags[aspix[ix] - 1] % 2 == 0) & (flags[ix] == 0) &
               (flags[ix] != 7))
        flags[np.where(cut == False)[0]] = 12

        # NOTE: If you wish to add a hook that filters the gPhoton output
        # (like perhaps by sky position or time range) then add it here.
        # I reccomend that you use the "ix = np.where" technique used above.
        # [Future]: Preprogram a (commented out) filter on RA/Dec.

        print_inline(chunkid + "Writing to spreadsheet...")

        # The issue is that we need to recombine the data into rows to
        # feed to csv.writerow, hence the loop.
        # It might be possible to do without a loop. One way would be
        # with numpy.column_stack except that this requires stupid
        # amounts of memory and therefore takes longer to run than the
        # loop iffen it manages to complete at all without a memory
        # error or segmentation fault.
        for i in range(len(t)):
            cnt += 1
            # To avoid repeat indexing of flags...
            thisflag = flags[i]
            # This substitutes empty strings for RA and Dec
            # values so that when they're dumped into the database
            # they are correctly recorded as NULL
            if (thisflag == 2 or thisflag == 5 or thisflag == 7
                    or thisflag == 8 or thisflag == 9 or thisflag == 10
                    or thisflag == 11 or thisflag == 12):
                # Should be:
                #if ((thisflag == 3) or (thisflag == 6) or (thisflag == 8) or
                #        (thisflag == 9) or (thisflag == 10) or
                #        (thisflag == 11) or (thisflag = 12):)
                if nullfile:
                    NULLspreadsheet.writerow([
                        int(t[i] * dbscale), x[i], y[i], xa[i], ya[i], q[i],
                        xi[i], eta[i], "", "", flags[i]
                    ])
                else:
                    spreadsheet.writerow([
                        int(t[i] * dbscale), x[i], y[i], xa[i], ya[i], q[i],
                        xi[i], eta[i], "", "", flags[i]
                    ])
            else:
                spreadsheet.writerow([
                    int(t[i] * dbscale), x[i], y[i], xa[i], ya[i], q[i], xi[i],
                    eta[i], ra[i], dec[i], flags[i]
                ])

    raw6hdulist.close()
    stopt = time.time()

    print_inline("")
    print("")
    print("Runtime statistics:")
    print(" runtime		=	{seconds} sec. = ({minutes} min.)".format(
        seconds=stopt - startt, minutes=(stopt - startt) / 60.))
    print("	processed	=	" + str(cnt) + " of " + str(nphots) + " events.")
    if cnt < nphots:
        print("		WARNING: MISSING EVENTS!")
    print("	rate		=	" + str(nphots / (stopt - startt)) + " photons/sec.")
    print("")

    return
예제 #11
0
def photonpipe(outbase, band, raw6file=None, scstfile=None, aspfile=None,
               ssdfile=None, nullfile=None, verbose=0, retries=20,
               eclipse=None):
    """
    Apply static and sky calibrations to -raw6 GALEX data, producing fully
        aspect-corrected and time-tagged photon list files.

    :param raw6file: Name of the raw6 file to use.

    :type raw6file: str

    :param scstfile: Spacecraft state file to use.

    :type scstfile: str

    :param band: Name of the band to use, either 'FUV' or 'NUV'.

    :type band: str

    :param outbase: Base of the output file names.

    :type outbase: str

    :param aspfile: Name of aspect file to use.

    :type aspfile: int

    :param ssdfile: Name of Stim Separation Data file to use.

    :type ssdfile: int

    :param nullfile: Name of output file to record NULL lines.

    :type nullfile: int

    :param verbose: Note used. Included for consistency with other tools.

    :type verbose: int

    :param retries: Number of query retries to attempt before giving up.

    :type retries: int
    """

    startt = time.time()

    # Scale factor for the time column in the output csv so that it
    # can be recorded as an int in the database.
    dbscale = 1000

    # This number determines the size of the chunks that gPhoton reads
    # in from the raw6 for processing. Even if your machine has a lot
    # of memory, making this number bigger is unlikely to improve the
    # processing time much because so much is eaten up by the .csv write.
    chunksz = 1000000

    # These are just constants for the mission.
    detsize = 1.25 # Detector size in degrees
    pltscl = 68.754932 # Plate scale
    aspum = pltscl/1000.0
    arcsecperpixel = 1.5
    xi_xsc, xi_ysc, eta_xsc, eta_ysc = 0., 1., 1., 0.

    # Determine the eclipse number from the raw6 header.
    if not raw6file:
        if not eclipse:
            raise ValueError('Must specifiy eclipse if no raw6file.')
        else:
            raw6file = download_data(
                        eclipse,band,'raw6',datadir=os.path.dirname(outbase))
            if raw6file==None:
                print('Unable to retrieve raw6 file for this eclipse.')
                return
    hdulist = pyfits.open(raw6file)
    hdr = hdulist[0].header
    hdulist.close()
    if eclipse and (eclipse!=hdr['eclipse']): # just a consistency check
        print("Warning: eclipse mismatch {e0} vs. {e1} (header)".format(
                                                e0=eclipse,e1=hdr['eclipse']))
    eclipse = hdr['eclipse']
    print("Processing eclipse "+str(eclipse)+".")

    # Returns detector constants.
    print("Band is "+band+".")
    (xclk, yclk, xcen, ycen, xscl, yscl, xslp,
     yslp) = clk_cen_scl_slp(band, eclipse)

    # This determines the values for the post-CSP detector stim scaling
    # and detector constant corrections.
    Mx, Bx, My, By, stimsep = 1, 0, 1, 0, 0
    if eclipse > 37460:
        (Mx, Bx, My, By, stimsep, yactbl) = compute_stimstats(raw6file, band,
                                                              eclipse)
        wig2, wig2data, wlk2, wlk2data, clk2, clk2data = post_csp_caldata()

    print("Loading wiggle files...")
    wiggle_x, _ = cal.wiggle(band, 'x')
    wiggle_y, _ = cal.wiggle(band, 'y')

    print("Loading walk files...")
    walk_x, _ = cal.walk(band, 'x')
    walk_y, _ = cal.walk(band, 'y')

    print("Loading linearity files...")
    linearity_x, _ = cal.linearity(band, 'x')
    linearity_y, _ = cal.linearity(band, 'y')

    # This is for the post-CSP stim distortion corrections.
    print("Loading distortion files...")
    if eclipse > 37460:
        print(" Using stim separation of :"+str(stimsep))
    distortion_x, disthead = cal.distortion(band, 'x', eclipse, stimsep)
    distortion_y, _ = cal.distortion(band, 'y', eclipse, stimsep)
    (cube_x0, cube_dx, cube_y0, cube_dy, cube_d0, cube_dd, cube_nd, cube_nc,
     cube_nr) = (disthead['DC_X0'], disthead['DC_DX'], disthead['DC_Y0'],
        disthead['DC_DY'], disthead['DC_D0'], disthead['DC_DD'],
        disthead['NAXIS3'], disthead['NAXIS1'], disthead['NAXIS2'])

    if band == 'FUV':
        if not scstfile:
            if not eclipse:
                raise ValueError('Must specifiy eclipse if no scstfile.')
            else:
                scstfile = download_data(
                        eclipse,band,'scst',datadir=os.path.dirname(outbase))
            if scstfile==None:
                print('Unable to retrieve SCST file for this eclipse.')
                return
        xoffset, yoffset = find_fuv_offset(scstfile)
    else:
        xoffset, yoffset = 0., 0.

    if os.path.isfile(str(ssdfile)):
        print("SSD file provided: "+str(ssdfile))
        stim_coef0, stim_coef1 = get_stim_coefs(ssdfile)
    elif ssdfile:
        print("SSD file requested: "+str(ssdfile))
        stim_coef0, stim_coef1 = create_ssd(raw6file, band, eclipse, ssdfile)
    else:
        print("No SSD file provided or requested.")
        stim_coef0, stim_coef1 = create_ssd(raw6file, band, eclipse)
    print("		stim_coef0, stim_coef1 = "+str(stim_coef0)+", "+str(stim_coef1))

    print("Loading mask file...")
    mask, maskinfo = cal.mask(band)
    npixx = mask.shape[0]
    npixy = mask.shape[1]
    pixsz = maskinfo['CDELT2']
    maskfill = detsize/(npixx*pixsz)

    print("Loading aspect data...")
    if aspfile:
        (aspra, aspdec, asptwist, asptime, aspheader,
         aspflags) = load_aspect(aspfile)
    else:
        (aspra, aspdec, asptwist, asptime, aspheader,
         aspflags) = web_query_aspect(eclipse, retries=retries)

    minasp, maxasp = min(asptime), max(asptime)
    trange = [minasp, maxasp]
    print("			trange= ( {t0} , {t1} )".format(t0=trange[0], t1=trange[1]))
    ra0, dec0, roll0 = aspheader['RA'], aspheader['DEC'], aspheader['ROLL']
    print("			[avgRA, avgDEC, avgROLL] = [{RA}, {DEC}, {ROLL}]".format(
        RA=aspra.mean(), DEC=aspdec.mean(), ROLL=asptwist.mean()))

    # This projects the aspect solutions onto the MPS field centers.
    print("Computing aspect vectors...")
    (xi_vec, eta_vec) = gnomfwd_simple(aspra, aspdec, ra0, dec0, -asptwist,
                                       1.0/36000.0, 0.)

    print("Loading raw6 file...")
    raw6hdulist = pyfits.open(raw6file, memmap=1)
    raw6htab = raw6hdulist[1].header
    nphots = raw6htab['NAXIS2']
    print("		"+str(nphots)+" events")
    cnt = 0

    outfile = outbase+'.csv'
    print("Preparing output file "+outfile)
    spreadsheet = csv.writer(open(outfile, 'w'), delimiter=',',
                             quotechar='|', quoting=csv.QUOTE_MINIMAL)

    # If specified, dump lines with NULLS into a separate csv file.
    if nullfile:
        nullfile = outbase+'_NULL.csv'
        print("Preparing output file "+nullfile)
        NULLspreadsheet = csv.writer(open(nullfile, 'w'), delimiter=',',
                                     quotechar='|', quoting=csv.QUOTE_MINIMAL)

    print("")

    for i in range(int(nphots/chunksz)+1):
        a = time.time() # Start the timer.

        csvrows = []
        chunkbeg, chunkend = i*chunksz, min(nphots,(i+1)*chunksz)

        chunkid = " "+str(i+1)+" of "+str(int(nphots/chunksz)+1)+": "
        print_inline(chunkid+"Unpacking raw6 data...")
        t = np.array(raw6hdulist[1].data.field('t')[chunkbeg:chunkend])
        phb1 = np.array(
            raw6hdulist[1].data.field('phb1')[chunkbeg:chunkend],dtype='int64')
        phb2 = np.array(
            raw6hdulist[1].data.field('phb2')[chunkbeg:chunkend],dtype='int64')
        phb3 = np.array(
            raw6hdulist[1].data.field('phb3')[chunkbeg:chunkend],dtype='int64')
        phb4 = np.array(
            raw6hdulist[1].data.field('phb4')[chunkbeg:chunkend],dtype='int64')
        phb5 = np.array(
            raw6hdulist[1].data.field('phb5')[chunkbeg:chunkend],dtype='int64')

        # Bitwise "decoding" of the raw6 telemetry.
        q = ((phb4 & 3) << 3) + ((phb5 & 224) >> 5)
        xb = phb1 >> 5
        xamc = (
            np.array(((phb1 & 31) << 7), dtype='int16') +
            np.array(((phb2 & 254) >> 1), dtype='int16') -
            np.array(((phb1 & 16) << 8), dtype='int16'))
        yb = ((phb2 & 1) << 2) + ((phb3 & 192) >> 6)
        yamc = (
            np.array(((phb3 & 63) << 6), dtype='int16') +
            np.array(((phb4 & 252) >> 2), dtype='int16') -
            np.array(((phb3 & 32) << 7), dtype='int16'))
        xa = ((phb5 & 16) >> 4) + ((phb5 & 3) << 3) + ((phb5 & 12) >> 1)
        xraw0 = xb*xclk + xamc
        yraw0 = yb*yclk + yamc
        ya = np.array(((((yraw0/(2*yclk) - xraw0/(2*xclk)) + 10)*32) + xa),
                      dtype='int64') % 32
        xraw = xraw0 + np.array((((xa+7) % 32) - 16), dtype='int64') * xslp
        yraw = yraw0 + np.array((((ya+7) % 32) - 16), dtype='int64') * yslp

        # Centering and scaling.
        x = (xraw - xcen)*xscl
        y = (yraw - ycen)*yscl

        # Post-CSP 'yac' corrections.
        if eclipse > 37460:
            x = Mx*x+Bx
            y = My*y+By
            yac = rtaph_yac(yactbl, ya, yb, yamc, eclipse)
            y = y-yac
            yac = rtaph_yac2(q, xb, yb, ya, y, aspum, wig2, wig2data, wlk2,
                             wlk2data, clk2, clk2data)
            y = y + yac

        # Empty these variables for memory management purposes.
        phb1,phb2,phb3,phb4,phb5,xb,xamc,yb,yamc,xraw0,yraw0,xraw,yraw=[[]]*13

        flags = np.zeros(len(t)) # initialized

        print_inline(chunkid+"Applying wiggle correction...")
        x_as = x*aspum
        y_as = y*aspum
        fptrx = x_as/10. + 240.
        fptry = y_as/10. + 240.

        x_as, y_as = [[]]*2 # Memory management.

        # This and other lines like it below are to verify that the
        # event is still on the detector.
        cut = ((fptrx > 0.) & (fptrx < 479.) & (fptry > 0.) & (fptry < 479.))
        flags[np.where((cut == False) & (flags == 0))[0]] = 8
        ix = np.where(cut == True)[0]

        fptrx_ix = np.array(fptrx, dtype='int64')
        fptry_ix = np.array(fptry, dtype='int64')
        blt = fptrx-fptrx_ix
        blu = fptry-fptry_ix
        wigx, wigy = np.zeros(len(t)), np.zeros(len(t))
        wigx[ix] = (
            (1-blt[ix])*(wiggle_x[xa[ix], fptrx_ix[ix]]) +
            (blt[ix])*(wiggle_x[xa[ix], fptrx_ix[ix]+1]))
        wigy[ix] = (
            (1-blu[ix])*(wiggle_y[ya[ix], fptry_ix[ix]]) +
            (blu[ix])*(wiggle_y[ya[ix], fptry_ix[ix]+1]))

        xdig = x + wigx/(10.*aspum)
        ydig = y + wigy/(10.*aspum)

        wigx, wigy = [[]]*2 # Memory management.

        print_inline(chunkid+"Applying walk correction...")
        xdig_as = xdig*aspum
        ydig_as = ydig*aspum
        fptrx = xdig_as/10. + 240.
        fptry = ydig_as/10. + 240.

        xdig_as, ydig_as = [[]]*2 # Memory management.

        cut = ((fptrx > 0.) & (fptrx < 479.) & (fptry > 0.) & (fptry < 479.))
        flags[np.where((cut == False) & (flags == 0))[0]] = 9
        ix = np.where(cut == True)[0]

        fptrx_ix = np.array(fptrx, dtype='int64')
        fptry_ix = np.array(fptry, dtype='int64')
        cut[ix] = ((walk_x[q[ix],fptry_ix[ix],fptrx_ix[ix]] != -999) |
                   (walk_x[q[ix],fptry_ix[ix],fptrx_ix[ix]+1] != -999) |
                   (walk_x[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]] != -999) |
                   (walk_x[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]+1] != -999) |
                   (walk_y[q[ix],fptry_ix[ix],fptrx_ix[ix]] != -999) |
                   (walk_y[q[ix],fptry_ix[ix],fptrx_ix[ix]+1] != -999) |
                   (walk_y[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]] != -999) |
                   (walk_y[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]+1] != -999))

        flags[np.where((cut == False) & (flags == 0))] = 9
        ix = np.where(cut == True)[0]

        fptrx_ix = np.array(fptrx, dtype='int64')
        fptry_ix = np.array(fptry, dtype='int64')
        blt = fptrx-fptrx_ix
        blu = fptry-fptry_ix
        walkx, walky = np.zeros(len(t)), np.zeros(len(t))
        walkx[ix] = (
            (1-blt[ix])*(1-blu[ix])*(walk_x[q[ix],fptry_ix[ix],fptrx_ix[ix]])+
            (blt[ix])*(1-blu[ix])*(walk_x[q[ix],fptry_ix[ix],fptrx_ix[ix]+1])+
            (1-blt[ix])*(blu[ix])*(walk_x[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]]) +
            (blt[ix])*(blu[ix])*(walk_x[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]+1]))
        walky[ix] = (
            (1-blt[ix])*(1-blu[ix])*(walk_y[q[ix],fptry_ix[ix],fptrx_ix[ix]]) +
            (blt[ix])*(1-blu[ix])*(walk_y[q[ix],fptry_ix[ix],fptrx_ix[ix]+1]) +
            (1-blt[ix])*(blu[ix])*(walk_y[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]]) +
            (blt[ix])*(blu[ix])*(walk_y[q[ix],fptry_ix[ix]+1,fptrx_ix[ix]+1]))

        print_inline(chunkid+"Applying spatial non-linearity correction...")
        xp = xdig - walkx
        yp = ydig - walky
        xp_as = xp*aspum
        yp_as = yp*aspum
        fptrx = xp_as/10. + 240.
        fptry = yp_as/10. + 240.

        xp, yp, walkx, walky = [[]]*4 # Memory management.

        cut = ((fptrx > 0.) & (fptrx < 479.) & (fptry > 0.) & (fptry < 479.))
        flags[np.where((cut == False) & (flags == 0))] = 10
        ix = np.where(cut == True)[0]

        fptrx_ix = np.array(fptrx, dtype='int64')
        fptry_ix = np.array(fptry, dtype='int64')
        blt = fptrx-fptrx_ix
        blu = fptry-fptry_ix

        dx, dy = np.zeros(len(t)), np.zeros(len(t))
        dx[ix] = (
            (1-blt[ix])*(1-blu[ix])*linearity_x[fptry_ix[ix],fptrx_ix[ix]]+
            (blt[ix])*(1-blu[ix])*linearity_x[fptry_ix[ix],fptrx_ix[ix]+1]+
            (1-blt[ix])*(blu[ix])*linearity_x[fptry_ix[ix]+1,fptrx_ix[ix]]+
            (blt[ix])*(blu[ix])*linearity_x[fptry_ix[ix]+1,fptrx_ix[ix]+1])
        dy[ix] = (
            (1-blt[ix])*(1-blu[ix])*linearity_y[fptry_ix[ix],fptrx_ix[ix]]+
            (blt[ix])*(1-blu[ix])*linearity_y[fptry_ix[ix],fptrx_ix[ix]+1]+
            (1-blt[ix])*(blu[ix])*linearity_y[fptry_ix[ix]+1,fptrx_ix[ix]]+
            (blt[ix])*(blu[ix])*linearity_y[fptry_ix[ix]+1,fptrx_ix[ix]+1])

        print_inline(chunkid+"Applying stim distortion correction...")

        ss = stim_coef0 + (t * stim_coef1) # stim separation
        col, row, depth = np.zeros(len(t)), np.zeros(len(t)), np.zeros(len(t))
        col[ix] = (xp_as[ix] - cube_x0) / cube_dx
        row[ix] = (yp_as[ix] - cube_y0) / cube_dy
        depth[ix] = (ss[ix] - cube_d0) / cube_dd

        # [Future]: This throws an error sometimes like the following, may need
        # fixing...
        """PhotonPipe.py:262: RuntimeWarning: invalid value encountered in
        less depth[((depth < 0)).nonzero()[0]] = 0.
        PhotonPipe.py:263: RuntimeWarning: invalid value encountered in
        greater_equal depth[((depth >= cube_nd)).nonzero()[0]] = -1.
        ERROR: IndexError: index -9223372036854775808 is out of bounds for
        axis 0 with size 17 [PhotonPipe]
        depth[((depth < 0)).nonzero()[0]] = 0.
        depth[((depth >= cube_nd)).nonzero()[0]] = -1.
        """

        cut = ((col > -1) & (col < cube_nc) & (row > -1) & (row < cube_nr) &
               (flags == 0) & (np.array(depth,dtype='int64')<18))
        flags[np.where(cut == False)[0]] = 11
        ix = np.where(cut == True)[0]

        xshift, yshift = np.zeros(len(t)), np.zeros(len(t))
        xshift[ix] = distortion_x[np.array(depth[ix], dtype='int64'),
            np.array(row[ix], dtype='int64'),np.array(col[ix], dtype='int64')]
        yshift[ix] = distortion_y[np.array(depth[ix], dtype='int64'),
            np.array(row[ix], dtype='int64'),np.array(col[ix], dtype='int64')]

        xshift = (xshift*arcsecperpixel)+xoffset
        yshift = (yshift*arcsecperpixel)+yoffset

        print_inline(chunkid+"Applying hotspot mask...")

        # The detectors aren't oriented the same way.
        flip = -1. if band=='FUV' else 1.

        xi = (
            xi_xsc*(flip*(yp_as + dy + yshift)*10.) +
            xi_ysc*(flip*(xp_as + dx + xshift)*10.))
        eta = (
            eta_xsc*(flip*(yp_as + dy + yshift)*10.) +
            eta_ysc*(flip*(xp_as + dx + xshift)*10.))

        xp_as,yp_as,depth,ss,dx,dy,xshift,yshift=[[]]*8 # Memory management.

        col = (((xi/36000.)/(detsize/2.)*maskfill + 1.)/2. * npixx)
        row = (((eta/36000.)/(detsize/2.)*maskfill + 1.)/2. * npixy)

        # Off detector at hotspot mask. Should mostly be stims.
        cut = ((col > 0.) & (col < 799.) & (row > 0.) & (row < 799.))
        flags[np.where((cut == False))] = 5 # Clobbers some earlier flags.
        ix = np.where(cut == True)[0]

        # Hotspot masks. Must use ix to prevent out-of-bounds error.
        cut[ix] = (mask[np.array(col, dtype='int64')[ix],
                    np.array(row, dtype='int64')[ix]] == 1.)
        flags[np.where((cut == False) & (flags == 0))] = 6
        ix = np.where(cut == True)[0]

        col, row = [[]]*2 # Memory management.

        # This gives the index of the aspect time that comes _before_
        # each photon time. Without the '-1' it will give the index
        # of the aspect time _after_ the photon time.
        print_inline(chunkid+"Mapping photon times to aspect times...")
        aspix = np.digitize(t, asptime)-1

        print_inline(chunkid+"Applying dither correction...")
        # Sky-project all data that are bracketed by aspect timestamps.
        cut = ((aspix > 0) & (aspix < (len(asptime)-1)))
        flags[np.where((cut == False) & ((flags==0) | (flags == 6)))] = 7
        ix = np.where(cut == True)[0]

        print_inline(chunkid+"Interpolating aspect solutions...")
        dxi, deta = np.zeros(len(t)), np.zeros(len(t))
        dxi[ix] = (
            (xi_vec[aspix[ix]+1]-xi_vec[aspix[ix]])*
            (t[ix]-asptime[aspix[ix]])/
            (asptime[aspix[ix]+1]-asptime[aspix[ix]]))
        deta[ix] = (
            (eta_vec[aspix[ix]+1]-eta_vec[aspix[ix]])*
            (t[ix]-asptime[aspix[ix]])/
            (asptime[aspix[ix]+1]-asptime[aspix[ix]]))

        print_inline(chunkid+"Mapping to sky...")
        ra, dec = np.zeros(len(t)), np.zeros(len(t))
        ra[ix], dec[ix] = gnomrev_simple(xi[ix]+dxi[ix], eta[ix]+deta[ix],
                aspra[aspix[ix]],aspdec[aspix[ix]],
                        -asptwist[aspix[ix]], 1/36000.,0.)

        # Flag data that do not have "good" aspect flags on both sides.
        #                       "Good" aspect solutions are divisible by 2.
        cut[ix] = (
            ((asptime[aspix[ix]+1]-asptime[aspix[ix]]) == 1) &
            (aspflags[aspix[ix]]%2 == 0) & (aspflags[aspix[ix]+1]%2 == 0) &
            (aspflags[aspix[ix]-1]%2 == 0) & (flags[ix] == 0) &
            (flags[ix] != 7) & (flags[ix] !=6))
        flags[np.where((cut == False) & (flags == 0))[0]] = 12

        # NOTE: If you wish to add a hook that filters the gPhoton output
        # (like perhaps by sky position or time range) then add it here.
        # [Future]: Preprogram a (commented out) filter on RA/Dec.

        print_inline(chunkid+"Writing to spreadsheet...")

        # There is a loop here because:
        #   we need to recombine the data into rows to feed to csv.writerow...
        #   numpy.column_stack requires a ton of memory and therefore takes
        #       longer to run than the loop...
        #   so there might be a more Pythonic way, but I don't know it. (cm)
        for i in range(len(t)):
            cnt += 1
            # To avoid repeat indexing of flags...
            thisflag = flags[i]
            # This substitutes empty strings for RA and Dec
            # values so that when they're dumped into the database
            # they are correctly recorded as NULL
            if thisflag in [2,5,7,8,9,10,11,12]:
                if nullfile:
                    NULLspreadsheet.writerow(
                        [int(t[i]*dbscale), x[i], y[i],xa[i], ya[i], q[i],
                         xi[i], eta[i], "", "", flags[i]])
                else:
                    spreadsheet.writerow(
                        [int(t[i]*dbscale), x[i], y[i], xa[i], ya[i], q[i],
                         xi[i], eta[i], "", "", flags[i]])
            else:
                spreadsheet.writerow(
                    [int(t[i]*dbscale), x[i], y[i], xa[i], ya[i], q[i], xi[i],
                     eta[i], ra[i], dec[i], flags[i]])

    raw6hdulist.close()
    stopt = time.time()

    print_inline("")
    print("")
    print("Runtime statistics:")
    print(" runtime		=	{seconds} sec. = ({minutes} min.)".format(
        seconds=stopt-startt, minutes=(stopt-startt)/60.))
    print("	processed	=	"+str(cnt)+" of "+str(nphots)+" events.")
    if cnt < nphots:
        print("		WARNING: MISSING EVENTS!") # This should never happen.
    print("	rate		=	"+str(nphots/(stopt-startt))+" photons/sec.")
    print("")

    return
예제 #12
0
def mcat_skybg(band,
               skypos,
               radius,
               verbose=0,
               trange=None,
               mcat=None,
               searchradius=0.1):
    """
    Estimate the sky background using the MCAT 'skybg' for nearby sources.

    :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 radius: The radius in which to search for MCAT sources in degrees.

    :type radius: float

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param trange: Minimum and maximum time (in GALEX time) to consider.

    :type trange: list

    :returns: float -- The estimated sky background in the photometric
        aperture, in counts per second.
    """
    # Search the visit-level MCAT for nearby detections.
    # Unless the MCAT data has already been handed off for detection purposes.
    if not mcat:
        mcat = get_mcat_data(skypos, searchradius)
    try:
        # Find the distance to each source.
        dist = np.array([
            angularSeparation(skypos[0], skypos[1], a[0], a[1])
            for a in zip(mcat[band]['ra'], mcat[band]['dec'])
        ])
    except TypeError:
        print_inline('No {b} MCAT sources within {r} degrees of {p}'.format(
            b=band, r=searchradius, p=skypos))
        return np.nan

    # Find visits that overlap in time.
    if not trange:
        tix = (np.array(list(range(len(mcat[band]['mag']))), dtype='int32'), )
    else:
        tix = np.where((
            (trange[0] >= mcat[band]['t0']) & (trange[0] <= mcat[band]['t1']))
                       | ((trange[1] >= mcat[band]['t0'])
                          & (trange[1] <= mcat[band]['t1']))
                       | ((trange[0] <= mcat[band]['t0'])
                          & (trange[1] >= mcat[band]['t1'])))

    if not len(tix[0]):
        print_inline('No concurrent {b} MCAT source nearby.'.format(b=band))
        return np.nan  # Might not be the preferred behavior here.

    ix = np.where(dist[tix] == min(dist[tix]))

    skybg = mcat[band]['skybg'][tix][ix]

    # This should rarely happen, but sometimes there's a duplicate entry in
    # the visit-level MCAT.
    if len(skybg) > 1:
        # If the skybg array is all the same value, it's a duplicate.
        if np.all(skybg == skybg[0]):
            skybg = np.asarray([skybg[0]])
        else:
            skybg = np.asarray([np.median(skybg)])

    return skybg[0] * area(radius * 60. * 60.)
예제 #13
0
def fGetTimeRanges(band,
                   skypos,
                   trange=None,
                   detsize=1.1,
                   verbose=0,
                   maxgap=1.,
                   minexp=1.,
                   skyrange=None,
                   maxgap_override=False,
                   minexp_override=False):
    """
    Find the contiguous time ranges within a time range at a specific location.

    :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 (in GALEX time) to consider.

    :type trange: list

    :param detsize: The effective detector diameter, in degrees.

    :type detsize: float

    :param verbose: Verbosity level, a value of 0 is minimum verbosity.

    :type verbose: int

    :param maxgap:  Maximum gap size, in seconds, for data to be considered
        contiguous.

    :type maxgap: float

    :param minexp: Minimum gap size, in seconds, for data to be considered
        contiguous.

    :type minexp: float

    :param skyrange: Values in degrees RA and Dec of a box around skypos that
        defines the extent of the region of interest.

    :type skyrange: list

    :param maxgap_override: Enables an experimental feature where maxgap
        can be less than one second.

    :type maxgap_override: bool

    :returns: numpy.ndarray -- A valid set of time ranges, accounting for
        minimum exposure lengths and maximum gaps.
	"""

    if trange is not None:
        trange_buffer = (trange[0] - 1, trange[1] + 1)
        times = get_valid_times(band,
                                skypos,
                                trange=trange_buffer,
                                detsize=detsize,
                                verbose=verbose,
                                skyrange=skyrange)
        if len(times):
            times = np.append(times, times[-1] + 1)
            if times[0] < trange[0]:
                times[0] = trange[0]
            if times[-1] > trange[1]:
                times[-1] = trange[1]
    else:
        times = get_valid_times(band,
                                skypos,
                                trange=None,
                                detsize=detsize,
                                verbose=verbose,
                                skyrange=skyrange)
        if len(times):
            times = np.append(times, times[-1] + 1)

    if not len(times):
        return np.array([[]], dtype='float64')

    if verbose:
        print_inline('Parsing ~' + str(len(times) - 1) +
                     ' seconds of raw exposure.')

    # NOTE: The minimum meaningful maxgap is 1 second.
    if maxgap < 1 and not maxgap_override:
        raise ValueError('maxgap must be >=1 second')

    tranges = distinct_tranges(times, maxgap=maxgap)

    if not minexp_override:
        ix = np.where(
            np.array(tranges)[:, 1] - np.array(tranges)[:, 0] >= minexp)
        tranges = np.array(tranges)[ix].tolist()

    return np.array(tranges, dtype='float64')
예제 #14
0
파일: CalUtils.py 프로젝트: parkus/gPhoton
def raw6_to_stims(raw6file, band, eclipse, margin=90.001):
    """
    Extracts stim events from a raw6 file.

    :param raw6file: The name of the raw6 FITS file to read.

    :type raw6file: str

    :param band: The band to return the stim data for, either 'FUV' or 'NUV'.

    :type band: str

    :param eclipse: The eclipse number to return the stim data for.

    :type eclipse: int

    :param margin: +/- extent in arcseconds defining stim search box

    :type margin: float

    :returns: tuple -- A four-element tuple containing data from each stim. The
        data from each stim are stored in dicts.
    """

    print("Extracting stim data from ", raw6file, " ...")
    print("         Using a search box with sides of ", margin, " arcseconds.")

    # This is unscoped for some reason... so I'm just coding it.
    (xclk, yclk, xcen, ycen, xscl, yscl, xslp, yslp) = clk_cen_scl_slp(band,
                                                                       eclipse)

    chunksz = 1000000
    print("Loading raw6 file...")
    raw6hdulist = pyfits.open(raw6file, memmap=1)
    raw6htab = raw6hdulist[1].header
    nphots = raw6htab['NAXIS2']

    stim1 = (
        {'t':np.array([]), 'q':np.array([]), 'xb':np.array([]),
         'xamc':np.array([]), 'yamc':np.array([]), 'xa':np.array([]),
         'ya':np.array([]), 'x':np.array([]), 'y':np.array([]),
         'yb':np.array([]), 'yap':np.array([])}
        )
    stim2 = (
        {'t':np.array([]), 'q':np.array([]), 'xb':np.array([]),
         'xamc':np.array([]), 'yamc':np.array([]), 'xa':np.array([]),
         'ya':np.array([]), 'x':np.array([]), 'y':np.array([]),
         'yb':np.array([]), 'yap':np.array([])}
        )
    stim3 = (
        {'t':np.array([]), 'q':np.array([]), 'xb':np.array([]),
         'xamc':np.array([]), 'yamc':np.array([]), 'xa':np.array([]),
         'ya':np.array([]), 'x':np.array([]), 'y':np.array([]),
         'yb':np.array([]), 'yap':np.array([])}
        )
    stim4 = (
        {'t':np.array([]), 'q':np.array([]), 'xb':np.array([]),
         'xamc':np.array([]), 'yamc':np.array([]), 'xa':np.array([]),
         'ya':np.array([]), 'x':np.array([]), 'y':np.array([]),
         'yb':np.array([]), 'yap':np.array([])}
        )

    print("")

    for i in range(int(nphots/chunksz)+1):
        csvrows = []
        chunkbeg, chunkend = i*chunksz, (i+1)*chunksz-1
        if chunkend > nphots:
            chunkend = nphots-1
        chunkid = " "+str(i+1)+" of "+str(int(nphots/chunksz)+1)+": "
        print_inline(chunkid+"Unpacking raw6 data...")
        t = np.array(raw6hdulist[1].data.field('t')[chunkbeg:chunkend])
        phb1 = np.array(
            raw6hdulist[1].data.field('phb1')[chunkbeg:chunkend], dtype='int64')
        phb2 = np.array(
            raw6hdulist[1].data.field('phb2')[chunkbeg:chunkend], dtype='int64')
        phb3 = np.array(
            raw6hdulist[1].data.field('phb3')[chunkbeg:chunkend], dtype='int64')
        phb4 = np.array(
            raw6hdulist[1].data.field('phb4')[chunkbeg:chunkend], dtype='int64')
        phb5 = np.array(
            raw6hdulist[1].data.field('phb5')[chunkbeg:chunkend], dtype='int64')

        q = ((phb4 & 3) << 3) + ((phb5 & 224) >> 5)
        xb = phb1 >> 5
        xamc = (np.array(((phb1 & 31) << 7), dtype='int16') +
                np.array(((phb2 & 254) >> 1), dtype='int16') -
                np.array(((phb1 & 16) << 8), dtype='int16'))
        yb = ((phb2 & 1) << 2) + ((phb3 & 192) >> 6)
        yamc = (np.array(((phb3 & 63) << 6), dtype='int16') +
                np.array(((phb4 & 252) >> 2), dtype='int16') -
                np.array(((phb3 & 32) << 7), dtype='int16'))
        xa = ((phb5 & 16) >> 4) + ((phb5 & 3) << 3) + ((phb5 & 12) >> 1)
        xraw0 = xb*xclk + xamc
        yraw0 = yb*yclk + yamc
        ya = (np.array(((((yraw0/(2*yclk) - xraw0/(2*xclk)) + 10)*32) + xa),
                       dtype='int64') % 32)
        xraw = (xraw0 + np.array((((xa+7) % 32) - 16), dtype='int64') * xslp)
        yraw = (yraw0 + np.array((((ya+7) % 32) - 16), dtype='int64') * yslp)
        x = (xraw - xcen)*xscl
        y = (yraw - ycen)*yscl

        index1, index2, index3, index4 = find_stims_index(x, y, band, eclipse,
                                                          margin)

        # [Future] There may well be a better way to do these assignments.
        stim1['t'] = np.append(stim1['t'], t[index1])
        stim1['x'] = np.append(stim1['x'], x[index1])
        stim1['y'] = np.append(stim1['y'], y[index1])
        stim1['q'] = np.append(stim1['q'], q[index1])
        stim1['xa'] = np.append(stim1['xa'], xa[index1])
        stim1['xb'] = np.append(stim1['xb'], ya[index1])
        stim1['ya'] = np.append(stim1['ya'], ya[index1])
        stim1['yb'] = np.append(stim1['yb'], yb[index1])
        stim1['xamc'] = np.append(stim1['xamc'], xamc[index1])
        stim1['yamc'] = np.append(stim1['yamc'], yamc[index1])
        stim1['yap'] = np.append(stim1['yap'], rtaph_yap(ya[index1],
                                                         yb[index1],
                                                         yamc[index1]))
        stim2['t'] = np.append(stim2['t'], t[index2])
        stim2['x'] = np.append(stim2['x'], x[index2])
        stim2['y'] = np.append(stim2['y'], y[index2])
        stim2['q'] = np.append(stim2['q'], q[index2])
        stim2['xa'] = np.append(stim2['xa'], xa[index2])
        stim2['xb'] = np.append(stim2['xb'], ya[index2])
        stim2['ya'] = np.append(stim2['ya'], ya[index2])
        stim2['yb'] = np.append(stim2['yb'], yb[index2])
        stim2['xamc'] = np.append(stim2['xamc'], xamc[index2])
        stim2['yamc'] = np.append(stim2['yamc'], yamc[index2])
        stim2['yap'] = np.append(stim2['yap'], rtaph_yap(ya[index2],
                                                         yb[index2],
                                                         yamc[index2]))
        stim3['t'] = np.append(stim3['t'], t[index3])
        stim3['x'] = np.append(stim3['x'], x[index3])
        stim3['y'] = np.append(stim3['y'], y[index3])
        stim3['q'] = np.append(stim3['q'], q[index3])
        stim3['xa'] = np.append(stim3['xa'], xa[index3])
        stim3['xb'] = np.append(stim3['xb'], ya[index3])
        stim3['ya'] = np.append(stim3['ya'], ya[index3])
        stim3['yb'] = np.append(stim3['yb'], yb[index3])
        stim3['xamc'] = np.append(stim3['xamc'], xamc[index3])
        stim3['yamc'] = np.append(stim3['yamc'], yamc[index3])
        stim3['yap'] = np.append(stim3['yap'], rtaph_yap(ya[index3],
                                                         yb[index3],
                                                         yamc[index3]))
        stim4['t'] = np.append(stim4['t'], t[index4])
        stim4['x'] = np.append(stim4['x'], x[index4])
        stim4['y'] = np.append(stim4['y'], y[index4])
        stim4['q'] = np.append(stim4['q'], q[index4])
        stim4['xa'] = np.append(stim4['xa'], xa[index4])
        stim4['xb'] = np.append(stim4['xb'], ya[index4])
        stim4['ya'] = np.append(stim4['ya'], ya[index4])
        stim4['yb'] = np.append(stim4['yb'], yb[index4])
        stim4['xamc'] = np.append(stim4['xamc'], xamc[index4])
        stim4['yamc'] = np.append(stim4['yamc'], yamc[index4])
        stim4['yap'] = np.append(stim4['yap'], rtaph_yap(ya[index4],
                                                         yb[index4],
                                                         yamc[index4]))

    print_inline("  Done.")

    return stim1, stim2, stim3, stim4
예제 #15
0
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