Exemple #1
0
    def __init__(self,
                 env,
                 x_init,
                 min_dist=.3,
                 nfourier=20,
                 t_horizon=2,
                 t_history=0,
                 mode='mi',
                 gui=True):
        self.x = x_init
        self.bounds = env.bounds
        self.u_max = env.get_u_max()
        self.min_dist = min_dist
        self.nfourier = nfourier
        self.t_horizon = t_horizon
        self.nagents = x_init.shape[0]
        self.tp_rate = env.tp_rate
        self.fp_rate = env.fp_rate
        self.u = [np.zeros((2, t_horizon)) for i in range(self.nagents)]

        K1, K2 = np.meshgrid(np.arange(nfourier),
                             np.arange(nfourier),
                             indexing='ij')
        self.k1 = K1.flatten() * np.pi
        self.k2 = K2.flatten() * np.pi

        self.hk = np.ones(self.k1.shape[0])
        self.hk[self.k1 != 0] *= np.sqrt(.5)
        self.hk[self.k2 != 0] *= np.sqrt(.5)

        s = (2 + 1) / 2
        self.Lambdak = (1 + np.square(self.k1) + np.square(self.k2))**(-s)

        self.t_history = t_history
        self.ck_history_cum = []

        r = env.target_r + env.view_r
        npix = int(np.ceil(r / env.grid_dx) * 2 + 1)
        reg = CirclePixelRegion(center=PixCoord(npix, npix),
                                radius=r / env.grid_dx)
        self.footprint_mask = reg.to_mask(mode='exact').data

        self.image1 = None
        self.image2 = None
        self.lines = None

        # self.change_paramt0 = 5
        # self.change_param = .01

        self.change_paramt0 = .1
        self.change_param = .01

        self.mode = mode
        self.gui = gui
Exemple #2
0
def makeMask(xs, ys, radius, cenx, ceny):
    shape = (xs, ys)
    fin_mask = np.zeros(shape)
    print(radius)
    for i in np.arange(len(cenx)):
        if radius[i] > 5:
            radius[i] = 6
        center = PixCoord(cenx[i], ceny[i])
        circle = CirclePixelRegion(center, radius[i] - 1)
        mask = circle.to_mask()
        newmask = mask.to_image(shape)
        fin_mask += newmask
    fin_mask[fin_mask > 1] = 1
    return fin_mask
Exemple #3
0
    def find_regions(self):
        """Find reflected regions."""
        curr_angle = self._angle + self._min_ang + self.min_distance_input
        reflected_regions = []
        while curr_angle < self._max_angle:
            test_pos = self._compute_xy(self._pix_center, self._offset, curr_angle)
            test_reg = CirclePixelRegion(test_pos, self._pix_region.radius)
            if not self._is_inside_exclusion(test_reg, self._distance_image):
                refl_region = test_reg.to_sky(self.exclusion_mask.wcs)
                log.debug('Placing reflected region\n{}'.format(refl_region))
                reflected_regions.append(refl_region)
                curr_angle = curr_angle + self._min_ang
            else:
                curr_angle = curr_angle + self.angle_increment

        log.info('Found {} reflected regions'.format(len(reflected_regions)))
        self.reflected_regions = reflected_regions
Exemple #4
0
    def test_regions_pixel(self):
        from regions import PixCoord, CirclePixelRegion

        # Out-of-bounds should still overlay the overlapped part.
        my_reg = CirclePixelRegion(center=PixCoord(x=6, y=2), radius=5)
        self.imviz.load_static_regions({'my_reg': my_reg})
        self.verify_region_loaded('my_reg')
        assert self.imviz.get_interactive_regions() == {}
Exemple #5
0
    def test_regions_fully_out_of_bounds(self):
        my_reg = CirclePixelRegion(center=PixCoord(x=100, y=100), radius=5)
        with pytest.warns(UserWarning, match='failed to load, skipping'):
            bad_regions = self.imviz.load_static_regions(
                {'my_oob_reg': my_reg})
        assert len(bad_regions) == 1

        # BUG: https://github.com/glue-viz/glue/issues/2275
        self.verify_region_loaded('my_oob_reg', count=1)  # Should be: count=0
Exemple #6
0
    def find_regions(self):
        """Find reflected regions."""
        curr_angle = self._angle + self._min_ang + self.min_distance_input
        reflected_regions = []
        while curr_angle < self._max_angle:
            test_pos = self._compute_xy(self._pix_center, self._offset, curr_angle)
            test_reg = CirclePixelRegion(test_pos, self._pix_region.radius)
            if not self._is_inside_exclusion(test_reg, self._distance_image):
                refl_region = test_reg.to_sky(self.reference_map.geom.wcs)
                log.debug("Placing reflected region\n{}".format(refl_region))
                reflected_regions.append(refl_region)
                curr_angle = curr_angle + self._min_ang
                if self.max_region_number <= len(reflected_regions):
                    break
            else:
                curr_angle = curr_angle + self.angle_increment

        log.debug("Found {} reflected regions".format(len(reflected_regions)))
        self.reflected_regions = reflected_regions
Exemple #7
0
def test_region_mask():
    mask = SkyImage.empty(nxpix=5, nypix=4)

    # Test with a pixel region
    region = CirclePixelRegion(center=PixCoord(x=2, y=1), radius=1.1)
    actual = mask.region_mask(region)
    expected = [
        [0, 0, 1, 0, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0],
    ]
    assert_equal(actual.data, expected)

    # Test with a sky region
    # Output is the same in this case, because the sky region
    # represents roughly the same region as the pixel region
    sky_region = region.to_sky(wcs=mask.wcs)
    actual = mask.region_mask(sky_region)
    assert_equal(actual.data, expected)
Exemple #8
0
def test_region_mask():
    mask = SkyImage.empty(nxpix=5, nypix=4)

    # Test with a pixel region
    region = CirclePixelRegion(center=PixCoord(x=2, y=1), radius=1.1)
    actual = mask.region_mask(region)
    expected = [
        [0, 0, 1, 0, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0],
    ]
    assert_equal(actual.data, expected)

    # Test with a sky region
    # Output is the same in this case, because the sky region
    # represents roughly the same region as the pixel region
    sky_region = region.to_sky(wcs=mask.wcs)
    actual = mask.region_mask(sky_region)
    assert_equal(actual.data, expected)
Exemple #9
0
    def test_wcslink_affine_with_extras(self):
        from regions import PixCoord, CirclePixelRegion

        self.imviz.link_data(link_type='wcs', wcs_fallback_scheme=None, error_on_fail=True)
        links = self.imviz.app.data_collection.external_links
        assert len(links) == 1
        assert isinstance(links[0], OffsetLink)

        # Customize display on second image (last loaded).
        self.imviz.set_colormap('viridis')
        self.imviz.stretch = 'sqrt'
        self.imviz.cuts = (0, 100)

        # Add subsets, both interactive and static.
        self.imviz._apply_interactive_region('bqplot:circle', (1.5, 2.5), (3.6, 4.6))
        self.imviz.load_static_regions({
            'my_reg': CirclePixelRegion(center=PixCoord(x=6, y=2), radius=5)})

        # Add markers.
        tbl = Table({'x': (0, 0), 'y': (0, 1)})
        self.imviz.add_markers(tbl, marker_name='xy_markers')
        assert 'xy_markers' in self.imviz.app.data_collection.labels

        # Run linking again, does not matter what kind.
        self.imviz.link_data(link_type='wcs', wcs_fallback_scheme=None, error_on_fail=True)

        # Ensure display is still customized.
        assert self.viewer.state.layers[1].cmap.name == 'viridis'
        assert self.viewer.state.layers[1].stretch == 'sqrt'
        assert_allclose((self.viewer.state.layers[1].v_min, self.viewer.state.layers[1].v_max),
                        (0, 100))

        # Ensure subsets are still there.
        assert 'Subset 1' in self.imviz.get_interactive_regions()
        assert 'my_reg' in [layer.layer.label for layer in self.viewer.state.layers]

        # Ensure markers are deleted.
        # Zoom and pan will reset in this case, so we do not check those.
        assert 'xy_markers' not in self.imviz.app.data_collection.labels
        assert len(self.imviz._marktags) == 0

        # Pan/zoom.
        self.imviz.center_on((5, 5))
        self.imviz.zoom_level = 0.789
        ans = (self.viewer.state.x_min, self.viewer.state.y_min,
               self.viewer.state.x_max, self.viewer.state.y_max)

        # Run linking again, does not matter what kind.
        self.imviz.link_data(link_type='wcs', wcs_fallback_scheme=None, error_on_fail=True)

        # Ensure pan/zoom does not change when markers are not present.
        assert_allclose((self.viewer.state.x_min, self.viewer.state.y_min,
                        self.viewer.state.x_max, self.viewer.state.y_max), ans)
Exemple #10
0
def angle_in_circle(image_filename, position_of_star, rht_data, radius):
    """ Gets a star, draws a circle around it and returns the average rht angle and standard deviation in this circle. """

    ipoints, jpoints, hthets, naxis1, naxis2, wlen, smr, thresh, thets_deg = rht_data

    c = CirclePixelRegion(PixCoord(
        np.round(position_of_star)[0],
        np.round(position_of_star)[1]),
                          radius=radius)

    # Check which RHT data is in this region, these are the indices:
    indices = c.contains(PixCoord(ipoints, jpoints))
    # hthets[indices] are all the pixel angle distributions found in the circle

    # Loop through pixels:
    # We multiply by thets_deg to get angle distribution, then normalise by dividing by the sum of the distribution, and finally take the sum of all values to get the average angle.
    average_on_pixel = []
    for i, v in enumerate(hthets[indices]):
        average_on_pixel.append(
            (hthets[indices][i] * thets_deg / hthets[indices][i].sum()).sum())

    return np.mean(average_on_pixel), np.std(average_on_pixel)
Exemple #11
0
    def test_regions_pixel(self):
        # A little out-of-bounds should still overlay the overlapped part.
        my_reg = CirclePixelRegion(center=PixCoord(x=6, y=2), radius=5)
        bad_regions = self.imviz.load_static_regions({'my_reg': my_reg})
        assert len(bad_regions) == 0
        self.verify_region_loaded('my_reg')

        # Unsupported shape but a valid region
        my_pt_reg = PointPixelRegion(center=PixCoord(x=1, y=1))
        with pytest.warns(UserWarning, match='failed to load, skipping'):
            bad_regions = self.imviz.load_static_regions(
                {'my_pt_reg': my_pt_reg})
        assert len(bad_regions) == 1
        self.verify_region_loaded('my_pt_reg', count=0)

        assert self.imviz.get_interactive_regions() == {}
Exemple #12
0
def pix_region(center=([49,49]), radius=5):
    '''
    Creat a region file, with pixel units
    
    Parameter
    --------
        center: The center of the region, with ([reg_x, reg_y]);
        radius: The radius of the region.
        
    Return
    --------
        A region which is ds9-like.
    '''
    center= PixCoord(x=center[0],y=center[1])
    region = CirclePixelRegion(center, radius)
    return region
Exemple #13
0
def cutout(filename, position, size, circ):
    """ Cut out a square of size size at center position position of the filename filename. Returns: the cut out filename, so it can be used in other scripts. """

    # Load the image and the WCS
    hdu = fits.open(filename)[0]
    naxis = hdu.header['NAXIS']
    wcs = WCS(hdu.header, naxis=naxis)

    # Make the cutout, including the WCS
    cutout = Cutout2D(hdu.data, position=position, size=size, wcs=wcs)

    # Put the cutout image in the FITS HDU
    hdu.data = cutout.data

    # Update the FITS header with the cutout WCS
    hdu.header.update(cutout.wcs.to_header())

    # Choose whether you want a circle or a square
    if (circ):
        # Define a circle region and keep only data that is in that region
        circle_pix = CirclePixelRegion(
            PixCoord(len(cutout.data[:, 1]) // 2,
                     len(cutout.data[1, :]) // 2),
            radius=np.min(size) / 2)  # region object
        for i in range(len(cutout.data[:, 1])):
            for j in range(len(cutout.data[1, :])):
                if not PixCoord(i, j) in circle_pix:
                    cutout.data[i, j] = 'nan'

        # Write the cutout to a new FITS file
        cutout_filename = filename.split(
            '.')[0] + '_cutout_circ.' + filename.split('.')[1]
        hdu.writeto(cutout_filename, overwrite=True)

        print("Made circle cutout, output: " + cutout_filename)

    else:
        # Write the cutout to a new FITS file
        cutout_filename = filename.split('.')[0] + '_cutout.' + filename.split(
            '.')[1]
        hdu.writeto(cutout_filename, overwrite=True)

        print("Made cutout, output: " + cutout_filename)

    # Return the output filename so we can use it in other scripts
    return cutout_filename
Exemple #14
0
def pix_region(center=[49.0, 49.0], radius=5):
    """
    Creat a region file, in pixel units.
    
    Parameter
    --------
        center: 
            The center of the region, with [reg_x, reg_y].
            
        radius: 
            The radius of the region.
    Return
    --------
        A region which is ds9-like.
    """
    center = PixCoord(x=center[0], y=center[1])
    region = CirclePixelRegion(center, radius)
    return region
Exemple #15
0
def _detail_check(eph, polygon_pix, observation_coords, start_date, end_date, radius=0.0083, aggressive_check=False):
    # A more detailed check for polygon footprint matching.
    # This checks each location in the original ephemerides and confirms if an observation intersects it

    flag = False
    for row in eph:
        if aggressive_check:
            if ((row['datetime_jd'] - 2400000.5) > end_date) or ((row['datetime_jd'] - 2400000.5) < start_date):
                flag = False
                continue

        target_coords = PixCoord(row['RA'], row['DEC'])
        if radius is None or radius < 0 and observation_coords is not None:
            flag = target_coords in polygon_pix
        else:
            target_circle = CirclePixelRegion(center=target_coords, radius=radius)
            flag = (target_coords in polygon_pix) or (observation_coords in target_circle)

        if flag:
            break

    return flag
Exemple #16
0
 def write_ds9_region_file(self, region_file):
     """Write a ds9-format region file (image coordinates) of
        the stars within the photometry table.
        
     """
     
     # TODO pick color based on Filter
     reg_color = 'red'
     pix_fmt   =  '.2f' # 0.01 pixels (for degrees use .6f)
     
     num_stars = len(self._phot_table)
     ap_radius = math.ceil(self._ap_fwhm_mult * self._search_fwhm)
     regions = []
     for x,y,id in zip(self._phot_table['xcenter'], 
         self._phot_table['ycenter'],
         self._phot_table['id']):
         # There is no need to convert from python 0-based to FITS
         # 1-based as the region class(es) do this for us.
         xpos      = x
         ypos      = y
         meta_dict = {'name': id}
         vis_dict  = {'color': reg_color}
         cpr       = CirclePixelRegion(center=PixCoord(xpos, ypos), 
             radius=ap_radius, 
             meta=meta_dict, 
             visual=vis_dict)
         regions.append( cpr )
     
     reg_str = ds9_objects_to_string(regions, 
         coordsys='image',
         fmt=pix_fmt,
         radunit='pix')
     with open(region_file, 'w', encoding='utf-8') as f_out:
         f_out.write(reg_str)
         
     self._logger.debug(f'Wrote ds9-format region file to {region_file}')
     return    
def read_sextractor(infile=None):
    '''
    This function will read in a sectractor output and return a list of regions. Working notes:
    - how do the SexTractor coordinates work? the test files ones don't make sense for MIRI.
    
    Input
    -----
    - infile: the sextractor output file
     
    '''

    # sextractor files can be read in with astropy.io.ascii hurrah
    t = ascii.read(infile)

    # now format each line into a CirclePixelRegion object
    coord_list = []

    for i in range(len(t)):
        reg = CirclePixelRegion(center=PixCoord(x=t['X_IMAGE'][i],
                                                y=t['Y_IMAGE'][i]),
                                radius=t['FWHM_IMAGE'][i] / 2.)
        coord_list.append(reg)

    return coord_list
    def __call__(self, abs_sci_name):
        '''
        PCA-based background subtraction, for a single frame so as to parallelize job

        INPUTS:
        abs_sci_name: science array filename
        '''

        # start the timer
        start_time = time.time()

        # read in the science frame from raw data directory
        sciImg, header_sci = fits.getdata(abs_sci_name, 0, header=True)

        # apply mask over weird detector regions to science image
        sciImg = np.multiply(sciImg, make_first_pass_mask(self.quad_choice))

        ## mask the PSF

        # define region
        psf_loc = find_airy_psf(sciImg)  # center of science PSF
        print("PSF location in " + os.path.basename(abs_sci_name) + ": [" +
              str(psf_loc[0]) + ", " + str(psf_loc[1]) + "]")
        radius = 30.  # radius around PSF that will be masked
        center = PixCoord(x=psf_loc[1], y=psf_loc[0])
        region = CirclePixelRegion(center, radius)
        mask_psf_region = region.to_mask()

        # apply the mask to science array
        psf_mask = np.ones(np.shape(
            sciImg))  # initialize arrays of same size as science image
        mask_psf_region.data[
            mask_psf_region.data ==
            1] = np.nan  # make zeros within mask cutout (but not in the mask itself) nans
        mask_psf_region.data[mask_psf_region.data == 0] = 1
        ##mask_psf_region.data[mask_psf_region.data == -99999] = 0 # have to avoid nans in the linear algebra
        psf_mask[
            mask_psf_region.bbox.
            slices] = mask_psf_region.data  # place the mask cutout (consisting only of 1s) onto the array of nans

        # I don't know why, but the sciImg nans in weird detector regions become zeros by this point, and I want them to stay nans
        # so, re-apply the mask over the bad regions of the detector
        sciImg = np.multiply(sciImg, make_first_pass_mask(self.quad_choice))

        sciImg_masked = np.multiply(
            sciImg, psf_mask)  # this is now the masked science frame

        # subtract the median (just a constant) from the remaining science image
        sciImg_psf_masked = np.subtract(
            sciImg_masked, np.nanmedian(sciImg_masked))  # where PSF is masked
        sciImg_psf_not_masked = np.subtract(
            sciImg, np.nanmedian(sciImg_masked))  # where PSF is not masked

        # apply the PSF mask to PCA slices, with which we will do the fitting
        pca_cube_masked = np.multiply(self.pca_cube, psf_mask)

        ## PCA-decompose

        # flatten the science array and PCA cube
        pca_not_masked_1ds = np.reshape(
            self.pca_cube,
            (np.shape(self.pca_cube)[0],
             np.shape(self.pca_cube)[1] * np.shape(self.pca_cube)[2]))
        sci_masked_1d = np.reshape(
            sciImg_psf_masked,
            (np.shape(sciImg_masked)[0] * np.shape(sciImg_masked)[1]))
        pca_masked_1ds = np.reshape(
            pca_cube_masked,
            (np.shape(pca_cube_masked)[0],
             np.shape(pca_cube_masked)[1] * np.shape(pca_cube_masked)[2]))

        ## remove nans from the linear algebra

        # indices of finite elements over a single flattened frame
        idx = np.logical_and(np.isfinite(pca_masked_1ds[0, :]),
                             np.isfinite(sci_masked_1d))

        # reconstitute only the finite elements together in another PCA cube and a science image
        pca_masked_1ds_noNaN = np.nan * np.ones(
            (len(pca_masked_1ds[:, 0]), np.sum(idx))
        )  # initialize array with slices the length of number of finite elements
        for t in range(
                0, len(pca_masked_1ds[:, 0])
        ):  # for each PCA component, populate the arrays without nans with the finite elements
            pca_masked_1ds_noNaN[t, :] = pca_masked_1ds[t, idx]
        sci_masked_1d_noNaN = np.array(1, np.sum(idx))  # science frame
        sci_masked_1d_noNaN = sci_masked_1d[idx]

        # the vector of component amplitudes
        soln_vector = np.linalg.lstsq(pca_masked_1ds_noNaN[0:self.n_PCA, :].T,
                                      sci_masked_1d_noNaN)

        # reconstruct the background based on that vector
        # note that the PCA components WITHOUT masking of the PSF location is being
        # used to reconstruct the background
        recon_backgrnd_2d = np.dot(self.pca_cube[0:self.n_PCA, :, :].T,
                                   soln_vector[0]).T
        # now do the same, but for the channel bias variation contributions only (assumes 32 elements only)
        recon_backgrnd_2d_channels_only_no_psf_masking = np.dot(
            self.pca_cube[0:32, :, :].T,
            soln_vector[0][0:32]).T  # without PSF masking
        recon_backgrnd_2d_channels_only_psf_masked = np.dot(
            self.pca_cube[0:32, :, :].T,
            soln_vector[0][0:32]).T  # with PSF masking

        # do the actual subtraction:
        # all-background subtraction
        sciImg_subtracted = np.subtract(sciImg_psf_not_masked,
                                        recon_backgrnd_2d)
        # background subtraction of channels only:
        # without PSF masking
        #sciImg_subtracted_channels_only_no_psf_masking = np.subtract(sciImg_psf_not_masked,recon_backgrnd_2d_channels_only)
        # with PSF masking
        sciImg_subtracted_channels_only_psf_masked = np.subtract(
            sciImg_psf_masked,
            np.multiply(recon_backgrnd_2d_channels_only_psf_masked,
                        np.multiply(self.pca_cube, psf_mask)))

        # add last reduction step to header
        header_sci["RED_STEP"] = "pca_background_subtracted"

        # save reconstructed background for checking
        abs_recon_bkgd = str(self.config_data["data_dirs"]["DIR_OTHER_FITS"] +
                             'recon_bkgd_quad_' +
                             str("{:0>2d}".format(self.quad_choice)) +
                             '_PCAseqStart_' +
                             str("{:0>6d}".format(self.cube_start_framenum)) +
                             '_PCAseqStop_' +
                             str("{:0>6d}".format(self.cube_stop_framenum)) +
                             '_' + os.path.basename(abs_sci_name))
        fits.writeto(filename=abs_recon_bkgd,
                     data=recon_backgrnd_2d,
                     overwrite=True)

        # save masked science frame BEFORE background-subtraction
        abs_masked_sci_before_bkd_subt = str(
            self.config_data["data_dirs"]["DIR_OTHER_FITS"] +
            'masked_sci_before_bkd_subt_quad_' +
            str("{:0>2d}".format(self.quad_choice)) + '_PCAseqStart_' +
            str("{:0>6d}".format(self.cube_start_framenum)) + '_PCAseqStop_' +
            str("{:0>6d}".format(self.cube_stop_framenum)) +
            os.path.basename(abs_sci_name))
        fits.writeto(filename=abs_masked_sci_before_bkd_subt,
                     data=sciImg_psf_masked,
                     overwrite=True)

        # save masked, background-subtracted science frame
        background_subtracted_masked = np.multiply(
            sciImg_subtracted, make_first_pass_mask(self.quad_choice))
        background_subtracted_masked = np.multiply(
            background_subtracted_masked, psf_mask)
        abs_masked_sci_after_bkd_subt = str(
            self.config_data["data_dirs"]["DIR_OTHER_FITS"] +
            'masked_sci_after_bkd_subt_quad_' +
            str("{:0>2d}".format(self.quad_choice)) + '_PCAseqStart_' +
            str("{:0>6d}".format(self.cube_start_framenum)) + '_PCAseqStop_' +
            str("{:0>6d}".format(self.cube_stop_framenum)) +
            os.path.basename(abs_sci_name))
        fits.writeto(filename=abs_masked_sci_after_bkd_subt,
                     data=background_subtracted_masked,
                     overwrite=True)

        # save background-subtracted science frame
        sciImg_subtracted_name = str(
            self.config_data["data_dirs"]["DIR_PCAB_SUBTED"] +
            os.path.basename(abs_sci_name))
        fits.writeto(filename=sciImg_subtracted_name,
                     data=sciImg_subtracted,
                     header=header_sci,
                     overwrite=True)
        print('Background-subtracted frame ' + os.path.basename(abs_sci_name) +
              ' written out. PCA = ' + str(self.n_PCA))

        ## make FYI plots of the effectiveness of the background subtraction
        # (N.b. the PSF and weird detector regions are masked here)
        self.vital_stats(file_base_name=str(os.path.basename(abs_sci_name)),
                         sci_img_pre=sciImg_masked,
                         sci_img_post_channel_subt=
                         sciImg_subtracted_channels_only_psf_masked,
                         sci_img_post_all_subt=background_subtracted_masked,
                         pca_spec=soln_vector[0])

        print('Elapsed time:')
        elapsed_time = time.time() - start_time
        print('--------------------------------------------------------------')
        print(elapsed_time)
Exemple #19
0
def clean_up_results(t_init, obj_name, id_type='smallbody', location=None, radius=0.0083):
    """
    Function to clean up results. Will check if the target is inside the observation footprint.
    If a radius is provided, will also construct a circle and check if the observation center is in the target circle.

    Parameters
    ----------
    t_init: atropy Table
        Initial astropy Table

    obj_name: str
        Object name. May require specific formatting (i.e. selecting between
       the codes for Jupiter and Jupiter barycenter). See JPL Horizons documentation

    id_type: str
        Object ID type for JPL Horizons. Defaults to smallbody (an asteroid or comet).
       Best to be as specific as possible to find the correct body.

       majorbody: planets and satellites
       smallbody: asteroids and comets
       asteroid_name: name of asteroid
       comet_name: name of comet
       name: any target name
       designation: any asteroid or comet designation

    location: str
        Default of None uses a geocentric location for queries.
       For specific spacecrafts, insert location

       Examples:
       TESS: @TESS
       Hubble: @hst
       Kepler: 500@-227

    radius : float
        Size of target for intersection calculations

    Returns
    -------
    t: astropy Table
        Astropy Table with only those where the moving target was in the footprint
    """

    t = t_init.copy()

    # Add mid-point time and sort by that first
    t['t_mid'] = (t['t_max'] + t['t_min'])/2 + 2400000.5
    t.sort('t_mid')

    # Ephemerides results are sorted by time, hence the initial sort
    print('Verifying footprints...')
    eph = Horizons(id=obj_name, location=location, id_type=id_type, epochs=t['t_mid']).ephemerides()

    # For each row in table, check s_region versus target position at mid-time
    check_list = []
    for i, row in enumerate(t):
        # print(row['t_mid'], eph['datetime_jd'][i], eph['RA'][i], eph['DEC'][i])

        # Create a polygon for the footprint and check if target is inside polygon
        try:
            stcs = parse_s_region(row['s_region'])
            xs = stcs['ra']
            ys = stcs['dec']
            polygon_pix = PolygonPixelRegion(vertices=PixCoord(x=xs, y=ys))
            target_coords = PixCoord(eph['RA'][i], eph['DEC'][i])
            if radius is None or radius <= 0:
                flag = target_coords in polygon_pix
            else:
                target_circle = CirclePixelRegion(center=target_coords, radius=radius)
                observation_coords = PixCoord(row['s_ra'], row['s_dec'])
                flag = (target_coords in polygon_pix) or (observation_coords in target_circle)
            # print(stcs, flag)
        except Exception as e:
            print(f"ERROR checking footprint for {row['obs_id']} with: {e}"
                  f"\nAssuming False")
            flag = False

        check_list.append(flag)

    # Set the flags
    t['in_footprint'] = check_list

    return t[t['in_footprint']]
Exemple #20
0
def clean_up_results(t_init, obj_name, orig_eph=None, id_type='smallbody', location=None, radius=0.0083,
                     aggressive_check=False):
    """
    Function to clean up results. Will check if the target is inside the observation footprint.
    If a radius is provided, will also construct a circle and check if the observation center is in the target circle.
    TODO: This is a buggy for several reasons:
          1- regions doesn't have intersection of polygons yet so valid observations are missed
          2- the mid point for observations like TESS can be days away from the target location
          3- the _detail_check function is effectively re-adding most of what it clears

    Parameters
    ----------
    t_init: atropy Table
        Initial astropy Table

    obj_name: str
        Object name. May require specific formatting (i.e. selecting between
       the codes for Jupiter and Jupiter barycenter). See JPL Horizons documentation

    orig_eph: astropy Table
        Original ephemerides table

    id_type: str
        Object ID type for JPL Horizons. Defaults to smallbody (an asteroid or comet).
       Best to be as specific as possible to find the correct body.

       majorbody: planets and satellites
       smallbody: asteroids and comets
       asteroid_name: name of asteroid
       comet_name: name of comet
       name: any target name
       designation: any asteroid or comet designation

    location: str
        Default of None uses a geocentric location for queries.
       For specific spacecrafts, insert location

       Examples:
       TESS: @TESS
       Hubble: @hst
       Kepler: 500@-227

    radius: float
        Size of target for intersection calculations

    aggressive_check: bool
        Perform additional time checks; can remove valid observations (Default: False)

    Returns
    -------
    t: astropy Table
        Astropy Table with only those where the moving target was in the footprint
    """

    if len(t_init) == 0:
        return None

    if radius is not None and not isinstance(radius, float):
        radius = float(radius)

    t = t_init.copy()

    # Sort by mid point time
    t['t_mid'] = (t['t_max'] + t['t_min']) / 2 + 2400000.5
    t.sort('t_mid')

    # Ephemerides results are sorted by time, hence the initial sort
    print('Verifying footprints...')

    # Fix for TESS
    if location is not None and location.upper() == '@TESS':
        print('Restriction for TESS observations')
        threshold = 2456778.50000  # 2018-05-01
        ind = t['t_mid'] > threshold
        t = t[ind]

    eph = Horizons(id=obj_name, location=location, id_type=id_type, epochs=t['t_mid']).ephemerides()

    # For each row in table, check s_region versus target position at mid-time
    check_list = []
    for i, row in enumerate(t):
        # print(row['t_mid'], eph['datetime_jd'][i], eph['RA'][i], eph['DEC'][i])

        # Create a polygon for the footprint and check if target is inside polygon
        try:
            stcs = parse_s_region(row['s_region'])
            xs = stcs['ra']
            ys = stcs['dec']
            polygon_pix = PolygonPixelRegion(vertices=PixCoord(x=xs, y=ys))
            target_coords = PixCoord(eph['RA'][i], eph['DEC'][i])
            observation_coords = PixCoord(row['s_ra'], row['s_dec'])
            if radius is None or radius < 0:
                flag = target_coords in polygon_pix
            else:
                target_circle = CirclePixelRegion(center=target_coords, radius=radius)
                flag = (target_coords in polygon_pix) or (observation_coords in target_circle)
            if orig_eph is not None and not flag:
                flag = _detail_check(orig_eph, polygon_pix, observation_coords,
                                     start_date=row['t_min'], end_date=row['t_max'],
                                     radius=radius, aggressive_check=aggressive_check)
            # print(row['obs_id'], flag)
        except Exception as e:
            print(f"ERROR checking footprint for {row['obs_id']} with: {e}"
                  f"\nAssuming False")
            flag = False

        check_list.append(flag)

    # Set the flags
    t['in_footprint'] = check_list

    return t[t['in_footprint']]
Exemple #21
0
                                    obj_name=obj_name,
                                    id_type=id_type,
                                    location=location)
print(filtered_results)

# Using regions
import matplotlib.pyplot as plt
from astropy.coordinates import SkyCoord
from regions import PixCoord, PolygonSkyRegion, PolygonPixelRegion, CirclePixelRegion

patch_xs = parse_s_region(stcs)['ra']
patch_ys = parse_s_region(stcs)['dec']
polygon_sky = PolygonSkyRegion(
    vertices=SkyCoord(patch_xs, patch_ys, unit='deg', frame='icrs'))

# Treating as pixels for simplicity (and since I have no WCS)
polygon_pix = PolygonPixelRegion(vertices=PixCoord(x=patch_xs, y=patch_ys))
PixCoord(eph['RA'][1], eph['DEC'][1]) in polygon_pix
radius = 0.0083
target_coords = PixCoord(eph['RA'][0], eph['DEC'][0])
target_circle = CirclePixelRegion(center=target_coords, radius=radius)
intersection = target_circle & polygon_pix
# intersection.area # not implemented yet

fig, ax = plt.subplots(figsize=(8, 4))
patch = polygon_pix.as_artist(facecolor='none', edgecolor='red', lw=2)
ax.add_patch(patch)
plt.plot([eph['RA'][1]], [eph['DEC'][1]], 'ko')
plt.xlim(84.2, 81.4)
plt.ylim(41.2, 41.5)
def fftMask(sciImg, wavel_lambda, plateScale):
    # sciImg: this is actually the FFT image, not the science detector image
    # wavel_lambda: wavelenth of the observation
    # plateScale: plate scale of the detector (asec/pixel)

    # make division lines separating different parts of the PSF
    line_M1diam_pixOnFFT = findFFTloc(8.25,
                                      np.shape(sciImg)[0], wavel_lambda,
                                      plateScale)
    line_center2center_pixOnFFT = findFFTloc(14.4,
                                             np.shape(sciImg)[0], wavel_lambda,
                                             plateScale)
    line_edge2edge_pixOnFFT = findFFTloc(22.65,
                                         np.shape(sciImg)[0], wavel_lambda,
                                         plateScale)

    # define circles
    circRad = 60  # pixels in FFT space
    circle_highFreqPerfect_L = CirclePixelRegion(center=PixCoord(
        x=line_center2center_pixOnFFT[0], y=0.5 * np.shape(sciImg)[0]),
                                                 radius=circRad)
    circle_highFreqPerfect_R = CirclePixelRegion(center=PixCoord(
        x=line_center2center_pixOnFFT[1], y=0.5 * np.shape(sciImg)[0]),
                                                 radius=circRad)
    circle_lowFreqPerfect = CirclePixelRegion(center=PixCoord(
        x=0.5 * np.shape(sciImg)[1], y=0.5 * np.shape(sciImg)[0]),
                                              radius=circRad)

    # define central rectangular region that includes all three nodes
    rect_pix = PolygonPixelRegion(
        vertices=PixCoord(x=[
            line_edge2edge_pixOnFFT[0], line_edge2edge_pixOnFFT[1],
            line_edge2edge_pixOnFFT[1], line_edge2edge_pixOnFFT[0]
        ],
                          y=[
                              line_M1diam_pixOnFFT[1], line_M1diam_pixOnFFT[1],
                              line_M1diam_pixOnFFT[0], line_M1diam_pixOnFFT[0]
                          ]))

    # make the masks
    mask_circHighFreq_L = circle_highFreqPerfect_L.to_mask()
    mask_circHighFreq_R = circle_highFreqPerfect_R.to_mask()
    mask_circLowFreq = circle_lowFreqPerfect.to_mask()
    mask_rect = rect_pix.to_mask()

    # apply the masks
    sciImg1 = np.copy(
        sciImg)  # initialize arrays of same size as science image
    sciImg2 = np.copy(sciImg)
    sciImg3 = np.copy(sciImg)
    sciImg4 = np.copy(sciImg)

    # region 1
    sciImg1.fill(np.nan)  # initialize arrays of nans
    mask_circHighFreq_L.data[
        mask_circHighFreq_L.data ==
        0] = np.nan  # make zeros within mask cutout (but not in the mask itself) nans
    sciImg1[
        mask_circHighFreq_L.bbox.
        slices] = mask_circHighFreq_L.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg1 = np.multiply(
        sciImg1,
        sciImg)  # 'transmit' the original science image through the mask

    # region 2
    sciImg2.fill(np.nan)  # initialize arrays of nans
    mask_circHighFreq_R.data[
        mask_circHighFreq_R.data ==
        0] = np.nan  # make zeros within mask cutout (but not in the mask itself) nans
    sciImg2[
        mask_circHighFreq_R.bbox.
        slices] = mask_circHighFreq_R.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg2 = np.multiply(
        sciImg2,
        sciImg)  # 'transmit' the original science image through the mask

    # region 3
    sciImg3.fill(np.nan)  # initialize arrays of nans
    mask_circLowFreq.data[
        mask_circLowFreq.data ==
        0] = np.nan  # make zeros within mask cutout (but not in the mask itself) nans
    sciImg3[
        mask_circLowFreq.bbox.
        slices] = mask_circLowFreq.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg3 = np.multiply(
        sciImg3,
        sciImg)  # 'transmit' the original science image through the mask

    # region 4
    sciImg4.fill(np.nan)  # initialize arrays of nans
    mask_rect.data[
        mask_rect.data ==
        0] = np.nan  # make zeros within mask cutout (but not in the mask itself) nans
    sciImg4[
        mask_rect.bbox.
        slices] = mask_rect.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg4 = np.multiply(
        sciImg4,
        sciImg)  # 'transmit' the original science image through the mask

    # return medians of regions under masks
    med_highFreqPerfect_L = np.nanmedian(sciImg1)
    med_highFreqPerfect_R = np.nanmedian(sciImg2)
    med_lowFreqPerfect = np.nanmedian(sciImg3)
    med_rect = np.nanmedian(sciImg4)

    # return normal vectors corresponding to [x,y,z] to surfaces (x- and y- components are of interest)
    normVec_highFreqPerfect_L = normalVector(sciImg1)
    normVec_highFreqPerfect_R = normalVector(sciImg2)
    normVec_lowFreqPerfect = normalVector(sciImg3)
    normVec_rect = normalVector(sciImg4)

    # generate images showing footprints of regions of interest
    # (comment this bit in/out as desired)
    '''
    plt.imshow(sciImg1, origin='lower')
    plt.show()
    
    plt.imshow(sciImg2, origin='lower')
    plt.show()
    
    plt.imshow(sciImg3, origin='lower')
    plt.show()
    
    plt.imshow(sciImg4, origin='lower')
    plt.show()
    
    plt.clf()
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    cax = ax.imshow(sciImg, origin="lower")
    ax.axhline(line_M1diam_pixOnFFT[0])
    ax.axhline(line_M1diam_pixOnFFT[1])
    ax.axvline(line_M1diam_pixOnFFT[0])
    ax.axvline(line_M1diam_pixOnFFT[1])
    ax.axvline(line_center2center_pixOnFFT[0])
    ax.axvline(line_center2center_pixOnFFT[1])
    ax.axvline(line_edge2edge_pixOnFFT[0]) 
    ax.axvline(line_edge2edge_pixOnFFT[1]) 
    ax.add_patch(circle_highFreqPerfect_L.as_patch(facecolor='none', edgecolor='blue')) 
    ax.add_patch(circle_highFreqPerfect_R.as_patch(facecolor='none', edgecolor='blue')) 
    ax.add_patch(circle_lowFreqPerfect.as_patch(facecolor='none', edgecolor='blue')) 
    ax.add_patch(rect_pix.as_patch(facecolor='none', edgecolor='red')) 
    cbar = fig.colorbar(cax)
    plt.savefig("junk.pdf")
    '''

    dictFFTstuff = {}
    dictFFTstuff["med_highFreqPerfect_L"] = med_highFreqPerfect_L
    dictFFTstuff["med_highFreqPerfect_R"] = med_highFreqPerfect_R
    dictFFTstuff["med_lowFreqPerfect"] = med_lowFreqPerfect
    dictFFTstuff["med_rect"] = med_rect
    # note vectors are [a,b,c] corresponding to the eqn Z = a*X + b*Y + c
    dictFFTstuff["normVec_highFreqPerfect_L"] = normVec_highFreqPerfect_L
    dictFFTstuff["normVec_highFreqPerfect_R"] = normVec_highFreqPerfect_R
    dictFFTstuff["normVec_lowFreqPerfect"] = normVec_lowFreqPerfect
    dictFFTstuff["normVec_rect"] = normVec_rect

    return dictFFTstuff
if not only_fulldisk_images:

	if(PRINTER.input_text("Automatically find most-intense region? [y/n]") == "y"):
		PRINTER.info_text("Identifying region")
		px = np.argwhere(MAPCUBE[0].data == MAPCUBE[0].data.max()) * u.pixel

		if len(px) > 1:
			temp = ndimage.measurements.center_of_mass(np.array(px))
			px = [px[int(temp[0] + 0.5)]]

		#########################

		center = PixCoord(x = 2048, y = 2048)
		radius = 1600
		region = CirclePixelRegion(center, radius)
		point = PixCoord(px[0][1], px[0][0])

		if not region.contains(point):
			PRINTER.info_text("Identified region is outside the solar disk")
			PRINTER.info_text("Defaulting to user selection...")
			INIT_COORD = cutout_selection(MAPCUBE)
		else:
			INIT_COORD = MAPCUBE[0].pixel_to_world(px[0][1], px[0][0])

		auto_sel = True
	
	else:
		INIT_COORD = cutout_selection(MAPCUBE)
		auto_sel = False
def fftMask(sciImg,wavel_lambda,plateScale,fyi_string=''):
    ''' 
    Take a FFT image, generate masks to select interesting areas of the FFT, and 
    return data about those areas (amplitudes, normal vectors, etc.)

    INPUTS:
    sciImg: this is actually the FFT image, not the science detector image
    wavel_lambda: wavelength of the observation
    plateScale: plate scale of the detector (asec/pixel)
    fyi_string: an FYI string that could be used for plots

    OUTPUTS:
    dictFFTstuff: dictionary with keys corresponding to different parts of the FFT
    '''

    # make division lines separating different parts of the PSF
    line_M1diam_pixOnFFT = findFFTloc(D,np.shape(sciImg)[0],wavel_lambda,plateScale)
    line_center2center_pixOnFFT = findFFTloc(B_c2c,np.shape(sciImg)[0],wavel_lambda,plateScale)
    line_edge2edge_pixOnFFT = findFFTloc(B_e2e,np.shape(sciImg)[0],wavel_lambda,plateScale)

    # define circles
    circRad = 60 # pixels in FFT space
    circle_highFreqPerfect_L = CirclePixelRegion(center=PixCoord(x=line_center2center_pixOnFFT[0], y=0.5*np.shape(sciImg)[0]), radius=circRad)
    circle_highFreqPerfect_R = CirclePixelRegion(center=PixCoord(x=line_center2center_pixOnFFT[1], y=0.5*np.shape(sciImg)[0]), radius=circRad)
    circle_lowFreqPerfect = CirclePixelRegion(center=PixCoord(x=0.5*np.shape(sciImg)[1], y=0.5*np.shape(sciImg)[0]), radius=circRad)

    # define central rectangular region that includes all three nodes
    rect_pix = PolygonPixelRegion(vertices=PixCoord(x=[line_edge2edge_pixOnFFT[0],line_edge2edge_pixOnFFT[1],line_edge2edge_pixOnFFT[1],line_edge2edge_pixOnFFT[0]], 
                                                       y=[line_M1diam_pixOnFFT[1],line_M1diam_pixOnFFT[1],line_M1diam_pixOnFFT[0],line_M1diam_pixOnFFT[0]]))

    # make the masks
    mask_circHighFreq_L = circle_highFreqPerfect_L.to_mask()
    mask_circHighFreq_R = circle_highFreqPerfect_R.to_mask()
    mask_circLowFreq = circle_lowFreqPerfect.to_mask()
    mask_rect = rect_pix.to_mask()

    ## apply the masks

    # initialize arrays of same size as science image
    sciImg1 = np.copy(sciImg)
    sciImg2 = np.copy(sciImg)
    sciImg3 = np.copy(sciImg)
    sciImg4 = np.copy(sciImg)

    # region 1: high-freq lobe, left
    sciImg1.fill(np.nan) # initialize arrays of nans
    mask_circHighFreq_L.data[mask_circHighFreq_L.data == 0] = np.nan    # make zeros within mask cutout (but not in the mask itself) nans
    sciImg1[mask_circHighFreq_L.bbox.slices] = mask_circHighFreq_L.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg1 = np.multiply(sciImg1,sciImg) # 'transmit' the original science image through the mask
    sciImg1 = sciImg1.filled(fill_value=np.nan) # turn all masked '--' elements to nans

    # region 2: high-freq lobe, right
    sciImg2.fill(np.nan) # initialize arrays of nans
    mask_circHighFreq_R.data[mask_circHighFreq_R.data == 0] = np.nan    # make zeros within mask cutout (but not in the mask itself) nans
    sciImg2[mask_circHighFreq_R.bbox.slices] = mask_circHighFreq_R.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg2 = np.multiply(sciImg2,sciImg) # 'transmit' the original science image through the mask
    sciImg2 = sciImg2.filled(fill_value=np.nan) # turn all masked '--' elements to nans

    # region 3: low-freq lobe
    sciImg3.fill(np.nan) # initialize arrays of nans
    mask_circLowFreq.data[mask_circLowFreq.data == 0] = np.nan    # make zeros within mask cutout (but not in the mask itself) nans
    sciImg3[mask_circLowFreq.bbox.slices] = mask_circLowFreq.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg3 = np.multiply(sciImg3,sciImg) # 'transmit' the original science image through the mask
    sciImg3 = sciImg3.filled(fill_value=np.nan) # turn all masked '--' elements to nans

    # region 4: rectangular region containing parts of all lobes
    sciImg4.fill(np.nan) # initialize arrays of nans
    mask_rect.data[mask_rect.data == 0] = np.nan    # make zeros within mask cutout (but not in the mask itself) nans
    sciImg4[mask_rect.bbox.slices] = mask_rect.data  # place the mask cutout (consisting only of 1s) onto the array of nans
    sciImg4 = np.multiply(sciImg4,sciImg) # 'transmit' the original science image through the mask
    sciImg4 = sciImg4.filled(fill_value=np.nan) # turn all masked '--' elements to nans

    # return medians of regions under masks
    med_highFreqPerfect_L = np.nanmedian(sciImg1)
    med_highFreqPerfect_R = np.nanmedian(sciImg2)
    med_lowFreqPerfect = np.nanmedian(sciImg3)
    med_rect = np.nanmedian(sciImg4)

    # return normal vectors corresponding to [x,y,z] to surfaces (x- and y- components are of interest)
    normVec_highFreqPerfect_L = normalVector(sciImg1)
    normVec_highFreqPerfect_R = normalVector(sciImg2)
    normVec_lowFreqPerfect = normalVector(sciImg3)
    normVec_rect = normalVector(sciImg4)

    # return stdev in each region
    std_highFreqPerfect_L = np.nanstd(sciImg1)
    std_highFreqPerfect_R = np.nanstd(sciImg2)
    std_lowFreqPerfect = np.nanstd(sciImg3)
    std_rect = np.nanstd(sciImg4)

    # generate images showing footprints of regions of interest
    # (comment this bit in/out as desired)

    # initialize dictionary to contain FFT data
    # N.b. all the info in this dictionary is EITHER for
    # the FFT amplitude OR the FFT phase, depending on what
    # the 'sciImg' is
    dictFFTstuff = {}

    # median of high-freq lobe on left side, within circular region centered around 
    # where a perfect high-freq lobe would be
    dictFFTstuff["med_highFreqPerfect_L"] = med_highFreqPerfect_L

    # median of right-side high-freq lobe
    dictFFTstuff["med_highFreqPerfect_R"] = med_highFreqPerfect_R

    # median of low-frequency lobe
    dictFFTstuff["med_lowFreqPerfect"] = med_lowFreqPerfect

    # median of rectangle that is drawn to contain both high- and low-freq lobes
    dictFFTstuff["med_rect"] = med_rect

    # stdev of the same regions
    dictFFTstuff["std_highFreqPerfect_L"] = std_highFreqPerfect_L

    # median of right-side high-freq lobe
    dictFFTstuff["std_highFreqPerfect_R"] = std_highFreqPerfect_R

    # median of low-frequency lobe
    dictFFTstuff["std_lowFreqPerfect"] = std_lowFreqPerfect

    # median of rectangle that is drawn to contain both high- and low-freq lobes
    dictFFTstuff["std_rect"] = std_rect

    # normal vectors to the high- and low- frequency 
    # note vectors are [a,b,c] corresponding to the eqn Z = a*X + b*Y + c
    dictFFTstuff["normVec_highFreqPerfect_L"] = normVec_highFreqPerfect_L
    dictFFTstuff["normVec_highFreqPerfect_R"] = normVec_highFreqPerfect_R
    dictFFTstuff["normVec_lowFreqPerfect"] = normVec_lowFreqPerfect
    dictFFTstuff["normVec_rect"] = normVec_rect

    return dictFFTstuff
Exemple #25
0
"""Example how to plot pixel regions on an image without WCS.
"""
import numpy as np
import matplotlib.pyplot as plt
from regions import PixCoord, CirclePixelRegion

fig, ax = plt.subplots()
region = CirclePixelRegion(center=PixCoord(x=3, y=5), radius=3)

data = np.arange(10 * 15).reshape((10, 15))
ax.imshow(data, cmap='gray', interpolation='nearest', origin='lower')
region.plot(ax=ax, color='red')
plt.show()
Exemple #26
0
    def to_object(self, subset):
        """
        Convert a glue Subset object to a astropy regions Region object.

        Parameters
        ----------
        subset : `glue.core.subset.Subset`
            The subset to convert to a Region object
        """
        data = subset.data

        if data.pixel_component_ids[0].axis == 0:
            x_pix_att = data.pixel_component_ids[1]
            y_pix_att = data.pixel_component_ids[0]
        else:
            x_pix_att = data.pixel_component_ids[0]
            y_pix_att = data.pixel_component_ids[1]

        subset_state = subset.subset_state

        if isinstance(subset_state, RoiSubsetState):

            roi = subset_state.roi
            if isinstance(roi, RectangularROI):
                xcen = 0.5 * (roi.xmin + roi.xmax)
                ycen = 0.5 * (roi.ymin + roi.ymax)
                width = roi.xmax - roi.xmin
                height = roi.ymax - roi.ymin
                return RectanglePixelRegion(PixCoord(xcen, ycen), width,
                                            height)
            elif isinstance(roi, PolygonalROI):
                return PolygonPixelRegion(PixCoord(roi.vx, roi.vy))
            elif isinstance(roi, CircularROI):
                return CirclePixelRegion(PixCoord(*roi.get_center()),
                                         roi.get_radius())
            elif isinstance(roi, EllipticalROI):
                return EllipsePixelRegion(PixCoord(roi.xc, roi.yc),
                                          roi.radius_x, roi.radius_y)
            elif isinstance(roi, PointROI):
                return PointPixelRegion(PixCoord(*roi.center()))
            elif isinstance(roi, RangeROI):
                return range_to_rect(data, roi.ori, roi.min, roi.max)

            elif isinstance(roi, AbstractMplRoi):
                temp_sub = Subset(data)
                temp_sub.subset_state = RoiSubsetState(x_pix_att, y_pix_att,
                                                       roi.roi())
                try:
                    return self.to_object(temp_sub)
                except NotImplementedError:
                    raise NotImplementedError(
                        "ROIs of type {0} are not yet supported".format(
                            roi.__class__.__name__))

            else:
                raise NotImplementedError(
                    "ROIs of type {0} are not yet supported".format(
                        roi.__class__.__name__))

        elif isinstance(subset_state, RangeSubsetState):
            if subset_state.att == x_pix_att:
                return range_to_rect(data, 'x', subset_state.lo,
                                     subset_state.hi)
            elif subset_state.att == y_pix_att:
                return range_to_rect(data, 'y', subset_state.lo,
                                     subset_state.hi)
            else:
                raise ValueError(
                    'Range subset state att should be either x or y pixel coordinate'
                )

        elif isinstance(subset_state, MultiRangeSubsetState):
            if subset_state.att == x_pix_att:
                ori = 'x'
            elif subset_state.att == y_pix_att:
                ori = 'y'
            else:
                message = 'Multirange subset state att should be either x or y pixel coordinate'
                raise ValueError(message)
            if len(subset_state.pairs) == 0:
                message = 'Multirange subset state should contain at least one range'
                raise ValueError(message)
            region = range_to_rect(data, ori, subset_state.pairs[0][0],
                                   subset_state.pairs[0][1])
            for pair in subset_state.pairs[1:]:
                region = region | range_to_rect(data, ori, pair[0], pair[1])
            return region

        elif isinstance(subset_state, PixelSubsetState):
            return PointPixelRegion(PixCoord(*subset_state.get_xy(data, 1, 0)))

        elif isinstance(subset_state, AndState):
            temp_sub1 = Subset(data=data)
            temp_sub1.subset_state = subset_state.state1
            temp_sub2 = Subset(data=data)
            temp_sub2.subset_state = subset_state.state2
            return self.to_object(temp_sub1) & self.to_object(temp_sub2)

        elif isinstance(subset_state, OrState):
            temp_sub1 = Subset(data=data)
            temp_sub1.subset_state = subset_state.state1
            temp_sub2 = Subset(data=data)
            temp_sub2.subset_state = subset_state.state2
            return self.to_object(temp_sub1) | self.to_object(temp_sub2)

        elif isinstance(subset_state, XorState):
            temp_sub1 = Subset(data=data)
            temp_sub1.subset_state = subset_state.state1
            temp_sub2 = Subset(data=data)
            temp_sub2.subset_state = subset_state.state2
            return self.to_object(temp_sub1) ^ self.to_object(temp_sub2)

        elif isinstance(subset_state, MultiOrState):
            temp_sub = Subset(data=data)
            temp_sub.subset_state = subset_state.states[0]
            region = self.to_object(temp_sub)
            for state in subset_state.states[1:]:
                temp_sub.subset_state = state
                region = region | self.to_object(temp_sub)
            return region

        else:
            raise NotImplementedError(
                "Subset states of type {0} are not supported".format(
                    subset_state.__class__.__name__))
Exemple #27
0
def find_reflected_regions(region,
                           center,
                           exclusion_mask=None,
                           angle_increment='0.1 rad',
                           min_distance='0 rad',
                           min_distance_input='0.1 rad'):
    """Find reflected regions.

    Converts to pixel coordinates internally.

    Parameters
    ----------
    region : `~regions.CircleSkyRegion`
        Region
    center : `~astropy.coordinates.SkyCoord`
        Rotation point
    exclusion_mask : `~gammapy.image.SkyImage`, optional
        Exclusion mask
    angle_increment : `~astropy.coordinates.Angle`
        Rotation angle for each step
    min_distance : `~astropy.coordinates.Angle`
        Minimal distance between to reflected regions
    min_distance_input : `~astropy.coordinates.Angle`
        Minimal distance from input region

    Returns
    -------
    regions : list of `~regions.SkyRegion`
        Reflected regions list
    """
    angle_increment = Angle(angle_increment)
    min_distance = Angle(min_distance)
    min_distance_input = Angle(min_distance_input)

    # Create empty exclusion mask if None is provided
    if exclusion_mask is None:
        exclusion_mask = make_default_exclusion_mask(center, exclusion_mask,
                                                     region)

    distance_image = exclusion_mask.distance_image

    reflected_regions_pix = list()
    wcs = exclusion_mask.wcs
    pix_region = region.to_pixel(wcs)
    pix_center = PixCoord(*center.to_pixel(wcs))

    # Compute angle of the ON regions
    dx = pix_region.center.x - pix_center.x
    dy = pix_region.center.y - pix_center.y
    offset = np.hypot(dx, dy)
    angle = Angle(np.arctan2(dx, dy), 'rad')

    # Get the minimum angle a Circle has to be moved in order to not overlap
    # with the previous one
    min_ang = Angle(2 * np.arcsin(pix_region.radius / offset), 'rad')

    # Add required minimal distance between two off regions
    min_ang += min_distance

    # Maximum allowed angle before the an overlap with the ON regions happens
    max_angle = angle + Angle('360 deg') - min_ang - min_distance_input

    # Starting angle
    curr_angle = angle + min_ang + min_distance_input

    while curr_angle < max_angle:
        test_pos = _compute_xy(pix_center, offset, curr_angle)
        test_reg = CirclePixelRegion(test_pos, pix_region.radius)
        if distance_image.lookup_pix(test_reg.center) > pix_region.radius:
            reflected_regions_pix.append(test_reg)
            curr_angle = curr_angle + min_ang
        else:
            curr_angle = curr_angle + angle_increment

    reflected_regions = [_.to_sky(wcs) for _ in reflected_regions_pix]
    return reflected_regions
Exemple #28
0
def find_reflected_regions(region,
                           center,
                           exclusion_mask=None,
                           angle_increment=None,
                           min_distance=None,
                           min_distance_input=None):
    """Find reflected regions.

    Converts to pixel coordinates internally.

    Parameters
    ----------
    region : `~regions.CircleSkyRegion`
        Region
    center : `~astropy.coordinates.SkyCoord`
        Rotation point
    exclusion_mask : `~gammapy.image.SkyMask`, optional
        Exclusion mask
    angle_increment : `~astropy.coordinates.Angle`
        Rotation angle for each step, default: 0.1 rad
    min_distance : `~astropy.coordinates.Angle`
        Minimal distance between to reflected regions, default: 0 rad
    min_distance_input : `~astropy.coordinates.Angle`
        Minimal distance from input region, default: 0.1 rad

    Returns
    -------
    regions : list of `~regions.SkyRegion`
        Reflected regions list
    """
    angle_increment = Angle('0.1 rad') if angle_increment is None else Angle(
        angle_increment)
    min_distance = Angle('0 rad') if min_distance is None else Angle(
        min_distance)
    min_distance_input = Angle(
        '0.1 rad') if min_distance_input is None else Angle(min_distance_input)

    # Create empty exclusion mask if None is provided
    if exclusion_mask is None:
        min_size = region.center.separation(center)
        binsz = 0.02
        npix = int((3 * min_size / binsz).value)
        exclusion_mask = SkyMask.empty(name='empty exclusion mask',
                                       xref=center.galactic.l.value,
                                       yref=center.galactic.b.value,
                                       binsz=binsz,
                                       nxpix=npix,
                                       nypix=npix,
                                       fill=1)

    reflected_regions_pix = list()
    wcs = exclusion_mask.wcs
    pix_region = region.to_pixel(wcs)
    pix_center = PixCoord(*center.to_pixel(wcs))

    # Compute angle of the ON regions
    dx = pix_region.center.x - pix_center.x
    dy = pix_region.center.y - pix_center.y
    offset = np.hypot(dx, dy)
    angle = Angle(np.arctan2(dx, dy), 'rad')

    # Get the minimum angle a Circle has to be moved in order to not overlap
    # with the previous one
    min_ang = Angle(2 * np.arcsin(pix_region.radius / offset), 'rad')

    # Add required minimal distance between two off regions
    min_ang += min_distance

    # Maximum allowd angle before the an overlap with the ON regions happens
    max_angle = angle + Angle('360deg') - min_ang - min_distance_input

    # Starting angle
    curr_angle = angle + min_ang + min_distance_input
    while curr_angle < max_angle:
        test_pos = _compute_xy(pix_center, offset, curr_angle)
        test_reg = CirclePixelRegion(test_pos, pix_region.radius)
        if not _is_inside_exclusion(test_reg, exclusion_mask):
            reflected_regions_pix.append(test_reg)
            curr_angle = curr_angle + min_ang
        else:
            curr_angle = curr_angle + angle_increment

    reflected_regions = [_.to_sky(wcs) for _ in reflected_regions_pix]
    log.debug('Found {} reflected regions:\n {}'.format(
        len(reflected_regions), reflected_regions))
    return reflected_regions