Example #1
0
    def add_to_skyimage(skyimage, image):
        """ Take in a two dimensional numpy array representing the
            fits data and put it into the skyimage. """
        temp = image.reshape(image.shape[0] * image.shape[1])

        wsdl = skyimage.get_wsdl()
        PythonUtilities.set_wsdl_weights(temp, wsdl)
        skyimage.set_wsdl(wsdl)
Example #2
0
 def __call__(self, v, skydir=None):
     sd = skydir or SkyDir(Hep3Vector(v[0], v[1], v[2]))
     rval = 0
     for band in self.bands:
         PythonUtilities.arclength(band.rvals, band.wsdl, sd)
         mask = band.rvals < band.max_rad
         rval += (band.psf(band.rvals[mask], density=True) *
                  band.pix_counts[mask]).sum()
     return rval
Example #3
0
 def __call__(self, v, skydir=None):
     """ copied from roi_tsmap.HealpixKDEMap """
     sd = skydir or SkyDir(Hep3Vector(v[0], v[1], v[2]))
     rval = 0
     for i, band in enumerate(self.bands):
         if not band.has_pixels: continue
         rvals = np.empty(len(band.wsdl), dtype=float)
         PythonUtilities.arclength(rvals, band.wsdl, sd)
         mask = rvals < self.r95[i]
         rval += (band.psf(rvals[mask]) * band.pix_counts[mask]).sum()
     return rval
Example #4
0
 def call2(self, v, skydir=None):
     sd = skydir or SkyDir(Hep3Vector(v[0], v[1], v[2]))
     rval = 0
     for band in self.bands:
         if band.photons == 0: continue
         band.rvals = np.empty(len(band.wsdl), dtype=float)
         PythonUtilities.arclength(band.rvals, band.wsdl, sd)
         mask = band.rvals < band.r99
         rval += (band.psf(band.rvals[mask], density=True) *
                  band.pix_counts[mask]).sum()
     return rval
Example #5
0
 def fill(self, skyfun):
     """ Evaluate skyfun along the internal grid and return the resulting array.
     
         In this process, the internal grid is transformed to the center of
         the ROI, and the skyfun evaluated for each of the resulting
         positions.
         
         The rotation is rather fast, likely no need to pre-compute.
     """
     v = np.empty(self.npix * self.npix)
     PythonUtilities.val_grid(v, self.lons, self.lats, self.center, skyfun)
     return v.reshape([self.npix, self.npix])
Example #6
0
    def extended_source_counts(self, extended_model):
        if type(extended_model) not in [
                ROIExtendedModel, ROIExtendedModelAnalytic
        ]:
            raise Exception("Unknown extended model.")

        roi = self.roi
        sm = extended_model.extended_source.model

        extended_counts = np.zeros_like(self.bin_centers_rad)

        for band, smaller_band in zip(self.selected_bands, self.smaller_bands):

            extended_model.set_state(smaller_band)

            if type(extended_model) == ROIExtendedModel:

                nside = RadialModel.get_nside(self.size, self.npix)

                temp_band = Band(nside)
                wsdl = WeightedSkyDirList(temp_band, self.center,
                                          np.radians(self.size), True)
                vals = extended_model._pix_value(wsdl)

                rvals = np.empty(len(wsdl), dtype=float)
                PythonUtilities.arclength(rvals, wsdl, self.center)

                # get average value in each ring by averaging values.
                fraction = np.histogram(rvals,weights=vals,bins=np.sqrt(self.bin_edges_rad))[0]/\
                           np.histogram(rvals,bins=np.sqrt(self.bin_edges_rad))[0]

                # multiply intensities by solid angle in ring
                fraction *= RadialModel.solid_angle_cone(np.radians(
                    self.size)) / self.npix

            elif type(extended_model) == ROIExtendedModelAnalytic:

                fraction = np.empty_like(self.bin_centers_rad)

                for i, (theta_min,
                        theta_max) in enumerate(self.theta_pairs_rad):

                    fraction[i]=extended_model._overlaps(self.center,band,theta_max) - \
                             extended_model._overlaps(self.center,band,theta_min)

            # total counts from source * fraction of PDF in ring = model predictions in each ring.
            extended_counts += band.expected(sm) * fraction

        return extended_counts
Example #7
0
    def fill(self):
        self.wsdl = self.skyimage.get_wsdl()

        self.solid_angle = np.radians(self.pixelsize)**2

        model_counts = np.zeros(len(self.wsdl), dtype=float)

        model_counts += self.all_point_source_counts()
        model_counts += self.all_diffuse_sources_counts()
        model_counts *= self.roi.phase_factor  # don't forget about the phase factor!
        #NB -- this will need to be fixed if want to account for bracketing IRFs

        PythonUtilities.set_wsdl_weights(model_counts, self.wsdl)

        self.skyimage.set_wsdl(self.wsdl)
Example #8
0
 def num_overlap(self,
                 band,
                 roi_dir,
                 ps_dir,
                 radius_in_rad=None,
                 override_pdf=None):
     roi_rad = radius_in_rad or band.radius_in_rad
     if self.cache_hash != hash(band):
         # fragile due to radius dep.
         self.set_dir_cache(band, roi_dir, roi_rad)
     if override_pdf is None:
         band.psf.cpsf.wsdl_val(self.cache_diffs, ps_dir, self.cache_wsdl)
     else:
         difference = np.empty(len(self.cache_wsdl))
         PythonUtilities.arclength(difference, self.cache_wsdl, roi_dir)
         self.cache_diffs = override_pdf(difference)
     return self.cache_diffs.sum() * band.b.pixelArea()
Example #9
0
    def setup_from_roi(self, hr, factor):

        band1 = hr.band
        band2 = Band(int(round(band1.nside() * factor)))
        rd = band1.dir(hr.index)

        # get pixels within a radius 10% greater than the base Healpix diagonal dimension
        radius = (np.pi / (3 * band1.nside()**2))**0.5 * 2**0.5 * 1.1
        wsdl = WeightedSkyDirList(band2, rd, radius, True)

        # then cut down to just the pixels inside the base Healpixel
        inds = np.asarray([band1.index(x) for x in wsdl])
        mask = inds == hr.index
        dirs = [wsdl[i] for i in xrange(len(mask)) if mask[i]]
        inds = np.asarray([band2.index(x) for x in dirs]).astype(int)

        # sanity check
        if abs(float(mask.sum()) / factor**2 - 1) > 0.01:
            print 'Warning: number of pixels found does not agree with expectations!'

        # loop through the bands and image pixels to calculate the KDE
        from libpointlike import DoubleVector
        #dv = DoubleVector()
        rvs = [np.empty(len(band.wsdl), dtype=float) for band in hr.roi.bands]
        img = np.zeros(len(inds))
        weights = [
            np.asarray([x.weight() for x in b.wsdl]).astype(int)
            for b in hr.roi.bands
        ]
        for idir, mydir in enumerate(dirs):
            #print 'Processing pixel %d'%(idir)
            for iband, band in enumerate(hr.roi.bands):
                PythonUtilities.arclength(band.rvals, band.wsdl, mydir)
                img[idir] += (band.psf(rvs[iband], density=True) *
                              weights[iband]).sum()

        self.band1 = band1
        self.band2 = band2
        self.previous_index = -1

        sorting = np.argsort(inds)
        self.inds = inds[sorting]
        self.img = img[sorting]

        self.index = hr.index
Example #10
0
    def otf_source_counts(self, bg):

        roi = self.roi

        mo = bg.smodel

        background_counts = np.zeros_like(self.bin_centers_rad)

        for band, smaller_band in zip(self.selected_bands, self.smaller_bands):

            ns, bg_points, bg_vector = ROIDiffuseModel_OTF.sub_energy_binning(
                band, bg.nsimps)

            nside = RadialModel.get_nside(self.size, self.npix)

            temp_band = Band(nside)
            wsdl = WeightedSkyDirList(temp_band, self.center,
                                      np.radians(self.size), True)

            ap_evals = np.empty([len(self.bin_centers_rad), len(bg_points)])

            for ne, e in enumerate(bg_points):

                bg.set_state(e, band.ct, smaller_band)

                rvals = np.empty(len(wsdl), dtype=float)
                PythonUtilities.arclength(rvals, wsdl, self.center)
                vals = bg._pix_value(wsdl)

                # get average value in each ring by averaging values.
                ap_evals[:,ne] = np.histogram(rvals,weights=vals,bins=np.sqrt(self.bin_edges_rad))[0]/\
                                 np.histogram(rvals,bins=np.sqrt(self.bin_edges_rad))[0]

            # multiply intensities by solid angle in ring
            ap_evals *= RadialModel.solid_angle_cone(np.radians(
                self.size)) / self.npix

            ap_evals *= bg_vector
            mo_evals = mo(bg_points)
            background_counts += (ap_evals * mo_evals).sum(axis=1)

        return background_counts
Example #11
0
    def __call__(self, skydir):
        """ This funciton is analogous to the BandCALDBPsf.__call__ function
            except that it always returns the density (probability per unit
            area). Also, it is different in that it takes in a skydir or WSDL 
            instead of a radial distance. """
        if isinstance(skydir, BaseWeightedSkyDirList):
            difference = np.empty(len(skydir), dtype=float)
            PythonUtilities.arclength(
                difference, skydir, self.extended_source.spatial_model.center)
            return self.val(difference)
        elif type(skydir) == np.ndarray:
            return self.val(skydir)
        elif type(skydir) == list and len(skydir) == 3:
            skydir = SkyDir(Hep3Vector(skydir[0], skydir[1], skydir[2]))

        elif type(skydir) == SkyDir:
            return float(
                self.val(
                    skydir.difference(
                        self.extended_source.spatial_model.center)))
        else:
            raise Exception("Unknown input to AnalyticConvolution.__call__()")
Example #12
0
    def _cache(self, skydir):
        """Cache results for a particular SkyDir.  Then can change the model
           minimal overhead."""

        if (skydir.ra() == self.cache_ra) and (skydir.dec() == self.cache_dec):
            return

        for i, band in enumerate(self.roi.bands):

            en, exp, pa = band.e, band.exp.value, band.b.pixelArea()

            # make a first-order correction for exposure variation
            band.ts_er = exp(skydir, en) / exp(self.rd, en)

            # unnormalized PSF evaluated at each data pixel
            PythonUtilities.arclength(band.rvals, band.wsdl, skydir)
            band.ts_pix_counts = pa * band.psf(band.rvals, density=True)

            # calculate overlap
            band.ts_overlap = self.ro(band, self.rd, skydir)

        self.cache_ra = skydir.ra()
        self.cache_dec = skydir.dec()
Example #13
0
    def __call__(self, skydir, v):
        """ Using v, an array of values that has been evaluated on the Grid (e.g., by fill),
            find the value(s) corresponding to skydir (can be single or a list) using
            bilinear interpolation.
            
            The skydir(s) are rotated onto the equatorial grid."""

        if hasattr(skydir, 'EQUATORIAL'): skydir = [skydir]
        rvals = np.empty(len(skydir) * 2, dtype=float)
        PythonUtilities.rot_grid(rvals, skydir, self.center)
        lon = rvals[::2]
        lat = rvals[1::2]
        if self.wrap:
            # adopt negative longitudes for the nonce; fine for calculating differences
            lon = np.where(lon > 180, lon - 360, lon)
        npix = self.npix - 1
        x = (self.lon0 - lon) / (self.delta_lon / npix)
        y = (lat - self.lat0) / (self.delta_lat / npix)
        #if np.any( (x<0) || (x > npix) || (y < 0) || (y > npix) ):
        #    return np.nan
        xlo, ylo = np.floor(x + 1e-6).astype(int), np.floor(y +
                                                            1e-6).astype(int)
        xhi, yhi = xlo + 1, ylo + 1
        dx = np.maximum(0, x - xlo)
        dy = np.maximum(0, y - ylo)
        v = np.asarray(v)
        if self.bounds_error:
            return v[xlo, ylo] * (1 - dx) * (1 - dy) + v[xlo, yhi] * (
                1 - dx) * dy + v[xhi, ylo] * dx * (1 - dy) + v[xhi,
                                                               yhi] * dx * dy
        else:
            return np.where((xlo<0) | (ylo<0) | (xhi>npix) | (yhi>npix),self.fill_value,
                           v[np.clip(xlo,0,npix),np.clip(ylo,0,npix)]*(1-dx)*(1-dy) + \
                           v[np.clip(xlo,0,npix),np.clip(yhi,0,npix)]*(1-dx)*dy + \
                           v[np.clip(xhi,0,npix),np.clip(ylo,0,npix)]*dx*(1-dy) + \
                           v[np.clip(xhi,0,npix),np.clip(yhi,0,npix)]*dx*dy)
Example #14
0
def rad_extract(eventfiles,
                center,
                radius_function,
                return_cols=['PULSE_PHASE'],
                cuts=None,
                apply_GTI=True,
                theta_cut=66.4,
                zenith_cut=105,
                return_indices=False):
    """ Extract events with a radial cut.
        Return specified columns and perform additional boolean cuts.

        Return is in form of a dictionary whose keys are column names
        (and 'DIFFERENCES') and values are numpy arrays with the column
        values.  These will have been concatenated if there are multiple
        FT1 files.

    =========   =======================================================
    Argument    Description
    =========   =======================================================
    eventfiles  -- a list of FT1 filenames
    center      -- a SkyDir giving the center of the radial cut
    radius_function -- can be either a float specifying a cookier cutter
                radial cut, or a function taking as arguments the energy
                and event_class and speciying the radius in degrees, e.g.

              def radius(energy,event_class):
                 return numpy.where(event_class,2,1)*(energy/1000)**-0.75

    =========   =======================================================
    Keyword     Description
    =========   =======================================================
    return_cols ['RA','DEC','ENERGY','EVENT_CLASS','PULSE_PHASE'] -
                a list of FT1 column names to return
    cuts        None - an optional list of boolean cuts to apply,
                e.g., ['ENERGY > 100']
                NB -- cuts not yet implemented!!
    no_cuts     [False] do not apply default zenith and incidence angle cuts
    apply_GTI   [True] accept or reject an event based on GTI if True;
                else ignore GTI
    return_indices [False] if True, return an array giving the index in the
                original file of each event; obviously only useful in the
                case of a single event file
    =========   =======================================================
    """
    if not hasattr(radius_function, '__call__'):
        simple_scalar = True
        rval = radius_function
        radius_function = lambda e, event_class: rval
    else:
        simple_scalar = False

    eventfiles = __FITS_parse__(eventfiles)

    from collections import defaultdict, deque
    coldict = defaultdict(deque)
    cols = {}
    cut_cols = ['ZENITH_ANGLE', 'THETA', 'TIME']
    keys = list(
        set(['RA', 'DEC', 'ENERGY', 'CONVERSION_TYPE'] + cut_cols +
            return_cols))
    accepted = 0
    total = 0

    for eventfile in eventfiles:
        #e = pf.open(eventfile,memmap=1)
        #nrows = e[1].data.shape[0]
        #e.close()
        nrows = pyfits.getheader(eventfile, 'EVENTS')['NAXIS2']

        for key in keys:
            cols[key] = np.empty(nrows, dtype=float)
            PythonUtilities.get_float_col(cols[key], eventfile, 'EVENTS', key)

        rad = radius_function(cols['ENERGY'], cols['CONVERSION_TYPE'])
        tmask = trap_mask(cols['RA'], cols['DEC'], center, rad)
        tmask &= (cols['ZENITH_ANGLE'] < zenith_cut) & (cols['THETA'] <
                                                        theta_cut)
        if apply_GTI:
            tmask &= get_gti_mask(eventfile, cols['TIME'])
            print 'GTI will remove %d of %d photons.' % (
                (~tmask).sum(), len(tmask))
        if simple_scalar:
            rmask, diffs = rad_mask(cols['RA'][tmask], cols['DEC'][tmask],
                                    center, rad)
        else:
            rmask, diffs = rad_mask(cols['RA'][tmask], cols['DEC'][tmask],
                                    center, rad[tmask])

        for key in keys:
            coldict[key].append(cols[key][tmask][rmask])
        if return_indices:
            if 'EVENT_INDICES' not in return_cols:
                return_cols.append('EVENT_INDICES')
            coldict['EVENT_INDICES'].append(
                np.arange(len(tmask))[tmask][rmask])
        coldict['DIFFERENCES'].append(diffs)
        accepted += tmask.sum()
        total += len(tmask)

    for key in coldict.keys():
        if (key in cut_cols) and not (key in return_cols):
            cols.pop(key)
            continue
        cols[key] = np.concatenate([x for x in coldict[key]])
        if key in INT_TYPES: cols[key] = cols[key].astype(int)

    print 'Cuts removed %d of %d photons.' % (total - accepted, total)
    return cols
Example #15
0
    def __call__(self,
                 skydir,
                 repeat_diffuse=False,
                 bright_source_mask=None,
                 no_cache=False):
        """Return the TS for the position on the sky given by the argument.
        
           bright_sources = a mask to select sources to include with the
           diffuse when generating the TS map.
           
           repeat_diffuse [False] -- if set to True, will assume that the PSF eval.
                                     has already been done and the function is
                                     being called again with a change to the diffuse.

           no_cache       [False] -- will never pre-compute the PSF
        """

        bands = self.roi.bands
        bsm = bright_source_mask
        offset = skydir.difference(self.roi.roi_dir)

        if not repeat_diffuse or no_cache:

            for i, band in enumerate(bands):

                en, exp, pa = band.e, band.exp.value, band.b.pixelArea()

                # make a first-order correction for exposure variation
                band.ts_er = exp(skydir, en) / exp(self.rd, en)

                # separation of data from position
                PythonUtilities.arclength(band.rvals, band.wsdl, skydir)

                # screen out pixels too far
                max_rad = min(band.radius_in_rad - offset, band.max_rad)
                band.ts_mask = band.rvals <= max_rad

                # evaluate PSF at pixels
                band.ts_pix_counts = pa * band.psf(band.rvals[band.ts_mask],
                                                   density=True)

                # calculate overlap
                #band.ts_overlap = self.ro(band,self.rd,skydir)
                band.ts_overlap = band.psf.integral(max_rad)

        if not repeat_diffuse:

            for i, band in enumerate(bands):

                # pre-calculate the "pixel" part
                if band.has_pixels:
                    band.ts_pix_term = (band.ps_all_pix_counts[band.ts_mask] + band.bg_all_pix_counts[band.ts_mask])/ \
                                       (band.ts_exp*band.ts_pix_counts)

        else:

            # include bright point sources and diffuse in the background model
            if bsm is not None:
                for i, band in enumerate(bands):
                    if band.has_pixels:
                        bps_term = (band.ps_counts[bsm] * band.overlaps[bsm] *
                                    band.ps_pix_counts[:, bsm]).sum(axis=1)
                        band.ts_pix_term = (bps_term + band.bg_all_pix_counts)[
                            band.ts_mask] / (band.ts_exp * band.ts_pix_counts)

            # include only the diffuse in the background model
            else:
                for i, band in enumerate(bands):
                    if band.has_pixels:
                        band.ts_pix_term = band.bg_all_pix_counts[
                            band.ts_mask] / (band.ts_exp * band.ts_pix_counts)

        # NB -- can save some computation by calculating f0/f1/f2 simultaneously, but it is
        # currently a minute fraction of the total time (above code dominates)
        J = np.log(10)

        def f0(n0, *args):
            n0 = 10**n0
            accum = 0
            for band in bands:
                pix_term = (band.pix_counts[band.ts_mask] *
                            np.log(1 + n0 / band.ts_pix_term)
                            ).sum() if band.has_pixels else 0
                ap_term = -n0 * band.ts_overlap * band.ts_exp * band.phase_factor
                accum += pix_term + ap_term
            return accum

        def f1(n0, *args):
            n0 = 10**n0
            accum = 0
            for band in bands:
                pix_term = -(band.pix_counts[band.ts_mask] *
                             (1 + band.ts_pix_term / n0)**-1
                             ).sum() if band.has_pixels else 0
                ap_term = n0 * band.ts_exp * band.ts_overlap * band.phase_factor
                accum += pix_term + ap_term
            return J * accum

        def f2(n0, *args):
            n0 = 10**n0
            accum = 0
            for band in bands:
                if band.has_pixels:
                    quot = band.ts_pix_term / n0
                    pix_term = -(band.pix_counts[band.ts_mask] * quot /
                                 (1 + quot)**2).sum()
                else:
                    pix_term = 0
                ap_term = n0 * band.ts_exp * band.ts_overlap * band.phase_factor
                accum += pix_term + ap_term
            return J * J * accum

        def TS(n0, *args):
            return 2 * f0(n0, *args)

        # assess along a grid of seed values to make sure we have a good starting position
        vals = [f0(x) for x in self.seeds]
        amax = np.argmax(vals)
        if amax == 0: return 0
        seed = self.seeds[
            amax] + 0.5  # for some reason, helps to start *above* the critical point

        # re-implementation of scipy version that uses half the calls!
        def my_newton(func, x0, fprime, tol=1e-2):
            p0 = x0
            for i in xrange(30):
                fval = func(x0)
                if fval == 0: return x0, True
                gval = fprime(x0)
                delt = fval / gval
                x0 -= delt
                if (abs(delt) < tol):
                    return x0, True
            return x0, False

        n0, conv = my_newton(f1, seed, fprime=f2)
        if conv: return TS(n0)
        else:
            print 'Warning! did not converge to a value or a value consistent with 0 flux.'
            print 'Trying again...'
            n0, conv = my_newton(f1, n0, fprime=f2)
            if conv:
                print 'Converged on 2nd Try'
                return TS(n0)
            print 'DID NOT CONVERGE AFTER TWO ATTEMPTS'
            return -1