Пример #1
0
def main():
    stars = genStars(6.0)
    sources = genSources()
    shape = (300, 500)
    image1 = make_gaussian_sources_image(shape, stars)
    image2 = make_gaussian_sources_image(shape, sources)

    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 8))
    ax1.imshow(image1, origin='lower', interpolation='nearest')
    ax2.imshow(image2, origin='lower', interpolation='nearest')
    plt.show()
Пример #2
0
def create_dataset(shape=(512, 512),
                   fwhm=12.5 * u.arcsec,
                   pixsize=2 * u.arcsec,
                   noise_level=1 * mJypb,
                   n_sources=50,
                   flux_min=1 * mJypb,
                   flux_max=10 * mJypb,
                   filename='fake_map.fits'):

    hits, uncertainty, mask = create_ancillary(shape,
                                               fwhm=None,
                                               noise_level=1 * mJypb)
    wcs = create_wcs(shape, pixsize=2 * u.arcsec, center=None)

    beam_std_pix = (fwhm / pixsize).decompose().value * gaussian_fwhm_to_sigma
    sources = create_fake_source(shape,
                                 wcs,
                                 beam_std_pix,
                                 flux_min=flux_min,
                                 flux_max=flux_max,
                                 n_sources=n_sources)

    sources_map = make_gaussian_sources_image(
        shape, sources) * sources['amplitude'].unit

    data = add_noise(sources_map, uncertainty)
    hdus = create_hdulist(data, hits, uncertainty, mask, wcs, sources, fwhm,
                          noise_level)

    hdus.writeto(filename, overwrite=True)
Пример #3
0
def drawpic(filename, data, ra, dec, radius, number):
    sigma_psf = 2.5
    sources = Table()
    size = np.size(data[:,0])
    x = ra
    y = dec
    x1 = x - radius
    x2 = x + radius
    y1 = y - radius
    y2 = y + radius
    sources['x_mean'] = (data[:,0] - x1) / radius / 2. * 256.
    sources['y_mean'] = (data[:,1] - y1) / radius / 2. * 256.
    sources['x_stddev'] = sigma_psf*np.ones(size)
    sources['y_stddev'] = sources['x_stddev']
    sources['theta'] = np.zeros(size)
    sources['flux'] = data[:,2] / np.min(data[:,2]) * 5000
    tshape = (256, 256)
    image = (make_gaussian_sources_image(tshape, sources) + \
            make_noise_image(tshape, distribution='poisson', mean=10.,
                         random_state=12) + \
            make_noise_image(tshape, distribution='gaussian', mean=0.,
                           stddev=10., random_state=12))

    plt.imshow(image, cmap='gray', extent = [x1, x2, y1, y2], interpolation='nearest',
           origin='lower') 
    plt.xlabel('RA(°)')
    plt.ylabel('DEC(°)')
    for i in range(size):
        plt.text(data[i,0],data[i,1],np.str(i), fontsize=12, color = 'w')
    plt.savefig('output/fig/' + np.str(number) + '/'+str(number)+'.jpg')
def stars(image, number, max_counts=10000, gain=1, fwhm=4):
    """
    Add some stars to the image.
    """
    # Most of the code below is a direct copy/paste from
    # https://photutils.readthedocs.io/en/stable/_modules/photutils/datasets/make.html#make_100gaussians_image

    flux_range = [max_counts / 10, max_counts]

    y_max, x_max = image.shape
    xmean_range = [0.1 * x_max, 0.9 * x_max]
    ymean_range = [0.1 * y_max, 0.9 * y_max]
    xstddev_range = [fwhm, fwhm]
    ystddev_range = [fwhm, fwhm]
    params = dict([('amplitude', flux_range),
                   ('x_mean', xmean_range),
                   ('y_mean', ymean_range),
                   ('x_stddev', xstddev_range),
                   ('y_stddev', ystddev_range),
                   ('theta', [0, 2 * np.pi])])

    sources = make_random_gaussians_table(number, params,
                                          seed=12345)

    star_im = make_gaussian_sources_image(image.shape, sources)

    return star_im
Пример #5
0
def test_find_center_noise_bad_guess():
    image = make_gaussian_sources_image(SHAPE, STARS)
    noise = make_noise_image(SHAPE, distribution='gaussian', mean=0, stddev=5)
    cen2 = spf.find_center(image + noise, [40, 50], max_iters=1)
    # Bad initial guess, noise, should take more than one try...
    with pytest.raises(AssertionError):
        np.testing.assert_allclose(cen2, [30, 40])
Пример #6
0
def test_find_center_noise_good_guess():
    image = make_gaussian_sources_image(SHAPE, STARS)
    noise = make_noise_image(SHAPE, distribution='gaussian', mean=0, stddev=5)
    # Trying again with several iterations should work
    cen3 = spf.find_center(image + noise, [31, 41], max_iters=10)
    # Tolerance chosen based on some trial and error
    np.testing.assert_allclose(cen3, [30, 40], atol=0.02)
Пример #7
0
def test_find_center_no_star():
    # No star anywhere near the original guess
    image = make_gaussian_sources_image(SHAPE, STARS)
    # Offset the mean from zero to avoid nan center
    noise = make_noise_image(SHAPE, distribution='gaussian',
                             mean=1000, stddev=5, random_state=RANDOM_SEED)
    cen = spf.find_center(image + noise, [50, 200], max_iters=10)
    assert (np.abs(cen[0] - 50) > 1) and (np.abs(cen[1] - 200) > 1)
Пример #8
0
 def test_best_center(self):
     table = Table()
     table["flux"] = [1000]
     table["x_mean"] = [299.5]
     table["y_mean"] = [299.5]
     arr = datasets.make_gaussian_sources_image((600, 600), table)
     result = find_best_center(arr, 3, [299.5, 299.5])
     self.assertTrue(np.allclose((result[0], result[1]), [299.5, 299.5]))
Пример #9
0
def comp_img(comps, posns, img_shape, pix_size=0.6):
    src_tab = Table()
    src_tab["amplitude"] = [1] * len(comps)
    src_tab["x_mean"] = posns[0]
    src_tab["y_mean"] = posns[1]
    src_tab["x_stddev"] = comps["Maj"] / pix_size / 2.355
    src_tab["y_stddev"] = comps["Min"] / pix_size / 2.355
    src_tab["theta"] = 90 - comps["PA"]
    return make_gaussian_sources_image(img_shape, src_tab)
Пример #10
0
    def add_gaussian_sources(self, within=(0, 1), cat_gen=pos_uniform, **kwargs):
        """Add gaussian sources into the map.

        Parameters
        ----------
        within : tuple of 2 int
            force the sources within this relative range in the map
        cat_gen : function (`pos_uniform`|`pos_gridded`|`pos_list`|...)
            the function used to generate the pixel positions and flux of the sources (see Notes below)
        **kwargs
            any keyword arguments to be passed to the `cat_gen` function

        Notes
        -----
        the `cat_gen` function is used to generate the list of x, y pixel positions and fluxes
        and must at least support the `shape=None, within=(0, 1), mask=None` arguments.
        """
        shape = self.shape

        x_mean, y_mean, peak_flux = cat_gen(shape=shape, within=within, mask=self.mask, **kwargs)

        nsources = x_mean.shape[0]

        sources = Table(masked=True)

        sources["amplitude"] = peak_flux.to(self.unit * u.beam)

        sources["x_mean"] = x_mean
        sources["y_mean"] = y_mean

        sources["x_stddev"] = np.ones(nsources) * self.beam.sigma_pix.value
        sources["y_stddev"] = np.ones(nsources) * self.beam.sigma_pix.value
        sources["theta"] = np.zeros(nsources)

        # Crude check to be within the finite part of the map
        if self.mask is not None:
            within_coverage = ~self.mask[sources["y_mean"].astype(int), sources["x_mean"].astype(int)]
            sources = sources[within_coverage]

        # Gaussian sources...
        self._data += make_gaussian_sources_image(shape, sources)

        # Add an ID column
        sources.add_column(Column(np.arange(len(sources)), name="fake_id"), 0)

        # Transform pixel to world coordinates
        a, d = self.wcs.pixel_to_world_values(sources["x_mean"], sources["y_mean"])
        sources.add_columns([Column(a * u.deg, name="ra"), Column(d * u.deg, name="dec")])

        sources["_ra"] = sources["ra"]
        sources["_dec"] = sources["dec"]

        # Remove unnecessary columns
        sources.remove_columns(["x_mean", "y_mean", "x_stddev", "y_stddev", "theta"])

        self.fake_sources = sources
Пример #11
0
def make_gaussian_im(x_size, y_size, fluxes=[100,1000,10000], x_pos=[500,250,750], y_pos=[300,80,460],std=[6,6,6]):
    shape = (x_size, y_size)
    table = Table()
    table['flux'] = fluxes
    table['x_mean'] = x_pos
    table['y_mean'] = y_pos
    table['x_stddev'] = std
    table['y_stddev'] = std
    image = make_gaussian_sources_image(shape, table)
    return image
Пример #12
0
 def __init__(self, noise_dev=1.0):
     self.image_shape = [400, 500]
     data_file = get_pkg_data_filename('data/test_sources.csv')
     self._sources = Table.read(data_file)
     self.mean_noise = self.sources['amplitude'].max() / 100
     self.noise_dev = noise_dev
     self._stars = make_gaussian_sources_image(self.image_shape,
                                               self.sources)
     self._noise = make_noise_image(self._stars.shape,
                                    mean=self.mean_noise,
                                    stddev=noise_dev)
Пример #13
0
    def _simulate_image(self, exp_time: float, open_shutter: bool) -> NDArray[Any]:
        """Simulate an image.

        Args:
            exp_time: Exposure time in seconds.
            open_shutter: Whether the shutter is opened.

        Returns:
            numpy array with image.
        """

        # get shape for image
        shape = (int(self.window[3]), int(self.window[2]))

        # create image with Gaussian noise for BIAS
        data = make_noise_image(shape, distribution="gaussian", mean=10, stddev=1.0)

        # non-zero exposure time?
        if exp_time > 0:
            # add DARK
            data += make_noise_image(shape, distribution="gaussian", mean=exp_time / 1e4, stddev=exp_time / 1e5)

            # add stars and stuff
            if open_shutter:
                # get solar altitude
                sun_alt = self.world.sun_alt

                # get mean flatfield counts
                flat_counts = 30000 / np.exp(-1.28 * (4.209 + sun_alt)) * exp_time

                # create flat
                data += make_noise_image(shape, distribution="gaussian", mean=flat_counts, stddev=flat_counts / 10.0)

                # get catalog with sources
                sources = self._get_sources_table(exp_time)

                # filter out all sources outside FoV
                sources = sources[
                    (sources["x_mean"] > 0)
                    & (sources["x_mean"] < shape[1])
                    & (sources["y_mean"] > 0)
                    & (sources["y_mean"] < shape[0])
                ]

                # create image
                data += make_gaussian_sources_image(shape, sources)

        # saturate
        data[data > 65535] = 65535

        # finished
        return cast(NDArray[Any], data).astype(np.uint16)
Пример #14
0
def make_noiseless_data(imager, imager_filter_name, star_table):
    """Generate noiseless data of star field. Based upon
    gunagala.make_noiseless_data, which currently doesn't do PSFs
    very well.

    Args:
        imager (gunagala.Imager): Instance of a gunagala imaging system.
        imager_filter_name (str): Filter to use for noiseless data.
        star_table (astropy.Table): Table of star coordinates and magnitudes.

    Returns:
        CCDData: Noiseless imaging data.
    """
    ucac_filter_name = f'{ imager_filter_name.upper() }mag'

    electrons = np.zeros(
        (imager.wcs._naxis2,
         imager.wcs._naxis1)) * u.electron / (u.second * u.pixel)

    # Calculate observed sky background
    sky_rate = imager.sky_rate[imager_filter_name]
    if hasattr(imager.sky, 'relative_brightness'):
        pixel_coords = imager.get_pixel_coords()
        relative_sky = imager.sky.relative_brightness(pixel_coords, obs_time)
        sky_rate = sky_rate * relative_sky
    electrons = electrons + sky_rate

    # compute stellar fluxes and locations
    star_rate = imager.ABmag_to_rate(
        star_table[ucac_filter_name].data * u.ABmag, imager_filter_name)
    pixel_coords = imager.wcs.all_world2pix(
        star_table['_RAJ2000'].data * u.deg,
        star_table['_DEJ2000'].data * u.deg, 0)

    table = Table()
    table['amplitude'] = star_rate.value
    table['x_mean'] = pixel_coords[0]
    table['y_mean'] = pixel_coords[1]
    table['x_stddev'] = np.ones(len(pixel_coords[0]))  # PSF width = 1 pixels
    table['y_stddev'] = np.ones(len(pixel_coords[0]))  # PSF width = 1 pixels
    table['theta'] = np.zeros(len(pixel_coords[0]))

    star_data = make_gaussian_sources_image(
        (imager.wcs._naxis2, imager.wcs._naxis1),
        table) * star_rate.unit / u.pixel

    electrons = electrons + star_data
    noiseless = CCDData(electrons, wcs=imager.wcs)

    return (noiseless)
Пример #15
0
def test_radial_profile():
    image = make_gaussian_sources_image(SHAPE, STARS)
    for row in STARS:
        cen = spf.find_center(image, (row['x_mean'], row['y_mean']),
                              max_iters=10)
        print(row)
        r_ex, r_a, radprof = spf.radial_profile(image, cen)
        r_exs, r_as, radprofs = spf.radial_profile(image,
                                                   cen,
                                                   return_scaled=False)

        # Numerical value below is integral of input 2D gaussian, 2pi A sigma^2
        expected_integral = 2 * np.pi * row['amplitude'] * row['x_stddev']**2
        np.testing.assert_allclose(radprofs.sum(), expected_integral, atol=50)
Пример #16
0
    def make_host_image(self, magnitude='default', noisy=True):
        table_target = Table()
        table_target['flux'] = np.random.poisson(
            [cnts_target.value, cnts_host.value])
        gpos = [
            np.random.uniform(high=image_shape[0]),
            np.random.uniform(high=image_shape[1])
        ]
        table_target['x_mean'] = [
            gpos[0] + np.random.uniform(low=target_dist_pixels.value,
                                        high=target_dist_pixels.value), gpos[0]
        ]
        table_target['y_mean'] = [
            gpos[1] + np.random.uniform(low=target_dist_pixels.value,
                                        high=target_dist_pixels.value), gpos[1]
        ]
        table_target['x_stddev'] = [(x_stddev / arcsec_per_pixel).value,
                                    (galaxy_shape[0] / arcsec_per_pixel).value]
        table_target['y_stddev'] = [(y_stddev / arcsec_per_pixel).value,
                                    (galaxy_shape[1] / arcsec_per_pixel).value]
        table_target['theta'] = np.random.uniform(high=2 * np.pi,
                                                  size=2) * u.radian

        table_target2 = table_target
        table_target2['flux'] = np.random.poisson(
            [cnts_target.value, cnts_host.value])

        image_target = make_gaussian_sources_image(image_shape,
                                                   Table(table_target[0]),
                                                   oversample=psf_oversample)
        image_host = make_gaussian_sources_image(image_shape,
                                                 Table(table_target[1]),
                                                 oversample=psf_oversample)

        image_host2 = make_gaussian_sources_image(image_shape,
                                                  Table(table_target2[1]),
                                                  oversample=psf_oversample)
Пример #17
0
def add_fake_stars(image,
                   expTime,
                   number=N_STARS,
                   max_counts=MAX_COUNTS,
                   sky_counts=SKY_LEVEL,
                   gain=GAIN):
    """
    Adds fake stars to a dark image from the CCD. Used for testing while not on-telescope

    Input:
    - image         The numpy array from the CCD.
    - number        The number of stars to add
    - max_counts    The max counts for the stars to have
    - sky_counts    Counts to use for adding sky background
    - gain          CCD gain
    - expTime       The exposure time of the raw image, to scale star brightness

    Output:
    - fakeData      A numpy array containing the fake star image
    """
    # create sky background
    sky_im = np.random.poisson(sky_counts * gain, size=image.shape) / gain

    #flux_range = [max_counts/10, max_counts] # this the range for brightness, flux or counts
    flux_range = [
        float(expTime) * (max_counts / 10),
        float(expTime) * (max_counts / 1)
    ]

    y_max, x_max = image.shape
    xmean_range = [0.1 * x_max,
                   0.9 * x_max]  # this is where on the chip they land
    ymean_range = [0.1 * y_max, 0.9 * y_max]
    xstddev_range = [
        4, 4
    ]  # this is a proxy for gaussian width, FWHM, or focus I think.
    ystddev_range = [4, 4]
    params = dict([('amplitude', flux_range), ('x_mean', xmean_range),
                   ('y_mean', ymean_range), ('x_stddev', xstddev_range),
                   ('y_stddev', ystddev_range), ('theta', [0, 2 * np.pi])])

    randInt = random.randint(11111, 99999)
    sources = make_random_gaussians_table(number, params, random_state=randInt)
    star_im = make_gaussian_sources_image(image.shape, sources)
    fakeData = image + sky_im + star_im
    return fakeData
Пример #18
0
def model2dG_build(self):
    """Function to fit a 2d-Gaussian to the built epsf
    """

    # TODO once build_epsf is working smoothly in each class rewrite
    try:
        self.epsf
        epsf = self.epsf  # the build_epsf
    except:
        epsf = self

    # use photutils 2d gaussian fit on the built epsf
    # TODO give option to restrict fit params, force xmean,ymean to be the ctr, constant to be zero
    gaussian = photutils.centroids.fit_2dgaussian(epsf.data)
    print(gaussian.param_names, gaussian.parameters)
    # unpack the parameters of fit
    constant, amplitude, x_mean, y_mean, x_stddev, y_stddev, theta = gaussian.parameters
    # Theta is in degrees, rotating the sigma_x,sigma_y ccw from +x

    # Put fit values into table
    # TODO the build_epsf is oversampled with respect to the fits image class data
    # ie the x_stddev, y_stddev are scaled by the oversampling
    # I think what makes the most sense is to rescale the build_epsf array, I'm not clear on how to do that
    table = Table()
    table['constant'] = [constant]
    table['amplitude'] = [amplitude]
    #table['flux'] = [flux] # if flux and amplitude flux is ignored
    table['x_mean'] = [x_mean]
    table['y_mean'] = [y_mean]
    table['x_stddev'] = x_stddev  #[x_stddev/epsf.oversampling[0]]
    table['y_stddev'] = y_stddev  #[y_stddev/epsf.oversampling[1]]
    # theta is a ccw rotation from +x in deg
    # ie the 2dgaussian grabs hold of a sigma_x sigma_y and then rotated
    table['theta'] = [theta]

    # get epsf of the model fit
    shape = epsf.shape
    modeled_epsf = make_gaussian_sources_image(shape, table)
    resid = modeled_epsf.data - epsf.data

    return gaussian, table, modeled_epsf
Пример #19
0
def test_find_center_no_noise_star_at_edge():
    # Trying to put the star at the edge of the initial guess
    image = make_gaussian_sources_image(SHAPE, STARS)
    cen = spf.find_center(image, [45, 65], max_iters=10)
    np.testing.assert_allclose(cen, [30, 40])
Пример #20
0
def test_find_center_no_noise_good_guess():
    image = make_gaussian_sources_image(SHAPE, STARS)
    # Good initial guess, no noise, should converge in one try
    cen1 = spf.find_center(image, (31, 41), max_iters=1)
    np.testing.assert_allclose(cen1, [30, 40])
Пример #21
0
    def prepare_image(self):
        """Creates the image that will be fetched."""

        # Default values
        exposure_params: Dict[str, Any] = dict(
            seed=None,
            shape=[
                self.state["lr_x"] - self.state["ul_x"],
                self.state["lr_y"] - self.state["ul_y"],
            ],
            sources=False,
            noise=False,
            apply_poison_noise=False,
        )

        if isinstance(self._exposure_params, list):
            if len(self._exposure_params) == 0:
                # If the simulation configuration doesn't include an "exposures"
                # section, just add some default noise.
                exposure_params["noise"] = {
                    "distribution": "gaussian",
                    "mean": 1000,
                    "stddev": 20.0,
                }
            else:
                this_exposure = self._exposure_params[self._exposure_idx]

                # If str, file is the image to return
                if isinstance(this_exposure, str):
                    data = astropy.io.fits.getdata(this_exposure)
                    return data

                exposure_params.update(this_exposure)

        image = numpy.zeros(exposure_params["shape"][::-1], dtype="float32")
        if "seed" in exposure_params and exposure_params["seed"] is not None:
            numpy.random.seed(exposure_params["seed"])

        if exposure_params["noise"]:
            image += make_noise_image(image.shape, **exposure_params["noise"])

        if exposure_params["sources"]:
            if "source_table" in exposure_params["sources"]:
                source_table = astropy.table.Table.read(
                    exposure_params["sources"]["source_table"])
            else:
                n_sources = exposure_params["sources"]["n_sources"]
                if isinstance(n_sources, list):
                    n_sources = numpy.random.randint(*n_sources)
                param_ranges = exposure_params["sources"]["param_ranges"]
                source_table = get_source_table(param_ranges, n_sources)

            source_image = make_gaussian_sources_image(
                image.shape,
                source_table=source_table,
            )
            source_image *= self.state["exposure_time"] / 1000.0
            image += source_image

            if exposure_params["apply_poison_noise"]:
                image = apply_poisson_noise(image,
                                            seed=exposure_params["seed"])

        assert isinstance(image, numpy.ndarray)

        image[image > 2**16] = 2**16 - 1

        self.image = image.astype("uint16")
Пример #22
0
def completeness_limit(self,
                       line,
                       StarFinder,
                       threshold,
                       distance_modulus,
                       limit=0.8,
                       max_sep=0.5,
                       oversize=1.,
                       exclude_region=None,
                       iterations=1,
                       n_sources=500,
                       plot=False,
                       **kwargs):
    '''determine completness limit 

    1. Insert mock sources of different brightness
    2. Run the source detection algorithm
    3. Compare mock sources to detected sources and determine
       the faintest sources that have been detected.

    Parameters
    ----------
    data : ndarray
        image with


    Returns
    -------
    Table
    '''

    daoargs = {
        k: kwargs.pop(k)
        for k in dict(kwargs)
        if k in inspect.signature(DAOStarFinder).parameters.keys()
    }

    for k, v in kwargs.items():
        logger.warning(f'unused kwargs: {k}={v}')

    data = getattr(self, line).copy()
    err = getattr(self, f'{line}_err').copy()
    PSF = getattr(self, 'PSF')
    tshape = data.shape

    if not np.any(exclude_region):
        exclude_region = np.zeros(data.shape, dtype=bool)
    else:
        print(
            f'masking {np.sum(exclude_region)/np.prod(exclude_region.shape)*100:.2f} % of the image'
        )

    #----------------------------------------------------------------
    # craete mock data
    #----------------------------------------------------------------

    try:
        wavelength = int(re.findall(r'\d{4}', line)[0])
        PSF_correction = correct_PSF(wavelength)
    except:
        PSF_correction = 0

    j = 0
    while j < iterations:
        #for i in range(iterations):

        logger.info(f'iteration {j+1} of {iterations}')

        mock_sources = Table(data=np.zeros((n_sources, 7)),
                             names=[
                                 'magnitude', 'flux', 'x_mean', 'y_mean',
                                 'x_stddev', 'y_stddev', 'theta'
                             ])
        mock_sources['magnitude'] = sample_pnlf(n_sources, distance_modulus,
                                                29.75)
        mock_sources['flux'] = 10**(-(mock_sources['magnitude'] + 13.74) /
                                    2.5) * 1e20

        # create a number of random points (more than we need because
        # some will fall in unobserved areas)
        f = 1.5  # create more points than we need
        while True:
            # number we create is f * number of sources we want /
            # (observed area / total area )
            N = f * n_sources / (np.sum(~np.isnan(PSF)) / np.prod(self.shape))
            indices = np.random.uniform((0, 0), self.shape, (int(N), 2))
            x_mean = indices[:, 1]
            y_mean = indices[:, 0]
            PSF_arr = np.array(
                [PSF[int(y), int(x)] for x, y in zip(x_mean, y_mean)])
            in_frame = ~np.isnan(PSF_arr)

            x_mean = x_mean[in_frame]
            y_mean = y_mean[in_frame]
            PSF_arr = PSF_arr[in_frame]

            if len(x_mean) > n_sources:
                x_mean = x_mean[:n_sources]
                y_mean = y_mean[:n_sources]
                PSF_arr = PSF_arr[:n_sources]
                break
            else:
                # it might happen that more points fall in unobserved
                # areas. In this case we have to repeat
                f *= 1.1

        mock_sources['x_mean'], mock_sources['y_mean'] = x_mean, y_mean
        # get PSF size at the generated position
        mock_sources['x_stddev'] = (
            PSF_arr - PSF_correction) * gaussian_fwhm_to_sigma * oversize
        mock_sources['y_stddev'] = mock_sources['x_stddev']
        mock_sources['amplitude'] = mock_sources['flux'] / (
            mock_sources['x_stddev'] * np.sqrt(2 * np.pi))

        logger.info(f'{len(mock_sources)} mock sources created')

        if plot:
            fig = plt.figure(figsize=(6, 6))
            ax = fig.add_subplot(111, projection=self.wcs)

            norm = simple_norm(data, 'linear', clip=False, max_percent=95)
            ax.imshow(data, norm=norm, cmap=plt.cm.Blues_r, origin='lower')
            len(mock_sources)
            positions = np.transpose(
                [mock_sources['x_mean'], mock_sources['y_mean']])
            apertures = CircularAperture(positions, r=6)
            ax.scatter(mock_sources['x_mean'],
                       mock_sources['y_mean'],
                       color='tab:red')
            #apertures.plot(color='tab:red',lw=.2, alpha=1,ax=ax)
            plt.show()

        mock_img = make_gaussian_sources_image(tshape, mock_sources)
        mock_img += data

        logger.info('mock sources inserted into image')

        #----------------------------------------------------------------
        # detection run
        #----------------------------------------------------------------
        for fwhm in np.unique(PSF[~np.isnan(PSF)]):
            # we create a mask for the current pointing (must be inverted)
            psf_mask = (PSF == fwhm)  #& (~np.isnan(PSF))
            source_mask = make_source_mask(
                data, nsigma=2, npixels=5, dilate_size=int(
                    3 * fwhm)) | ~psf_mask
            mean, median, std = sigma_clipped_stats(data,
                                                    sigma=3.0,
                                                    maxiters=5,
                                                    mask=source_mask)

            # initialize and run StarFinder (DAOPHOT or IRAF)
            finder = StarFinder(fwhm=(fwhm - PSF_correction) * oversize,
                                threshold=threshold * std,
                                **daoargs)
            peaks_part = finder(mock_img, mask=(~psf_mask | exclude_region))

            if peaks_part:
                #logger.info(f'fwhm={fwhm:.3f}: {len(peaks_part)} sources found')
                if 'peak_tbl' in locals():
                    peaks_part['id'] += np.amax(peak_tbl['id'], initial=0)
                    peak_tbl = vstack([peak_tbl, peaks_part])
                else:
                    peak_tbl = peaks_part
            else:
                logger.info(f'fwhm={fwhm:>7.3f}: no sources found')

        if 'peak_tbl' in locals():
            logger.info(f'{len(peak_tbl)} sources found')
        else:
            logger.warning('no sources found')
            continue

        #----------------------------------------------------------------
        # compare detected sources to known mock stars
        #----------------------------------------------------------------
        logger.info(f'compare detected sources to injected sources')

        idx, sep = match_catalogues(mock_sources[['x_mean', 'y_mean']],
                                    peak_tbl[['xcentroid', 'ycentroid']])
        mock_sources['sep'] = sep
        mock_sources['peak'] = peak_tbl[idx]['peak']

        if 'out' in locals():
            out = vstack([out, mock_sources])
        else:
            out = mock_sources

        del peak_tbl
        j += 1

    #----------------------------------------------------------------
    # create the histogram
    #----------------------------------------------------------------

    filename = basedir / 'reports' / self.name / f'{self.name}_completness.pdf'
    plot_completeness_limit(out,
                            max_sep=max_sep,
                            limit=limit,
                            filename=filename)

    #----------------------------------------------------------------

    for col in out.colnames:
        out[col].info.format = '%.8g'

    return out
Пример #23
0
from astropy.table import Table
from photutils.datasets import (make_random_gaussians_table, make_noise_image,
                                make_gaussian_sources_image)

sigma_psf = 2.0
sources = Table()
sources['flux'] = [700, 800, 700, 800]
sources['x_mean'] = [12, 17, 12, 17]
sources['y_mean'] = [15, 15, 20, 20]
sources['x_stddev'] = sigma_psf * np.ones(4)
sources['y_stddev'] = sources['x_stddev']
sources['theta'] = [0, 0, 0, 0]
sources['id'] = [1, 2, 3, 4]
tshape = (32, 32)
image = (
    make_gaussian_sources_image(tshape, sources) +
    make_noise_image(tshape, distribution='poisson', mean=6., random_state=1) +
    make_noise_image(
        tshape, distribution='gaussian', mean=0., stddev=2., random_state=1))

from matplotlib import rcParams

rcParams['font.size'] = 13
import matplotlib.pyplot as plt

plt.imshow(image,
           cmap='viridis',
           aspect=1,
           interpolation='nearest',
           origin='lower')
plt.title('Simulated data')
Пример #24
0
def fake_image(n_sources=100,
               shape=[512, 512],
               amplitude_r=[0, 20000],
               std_dev=[0, 7],
               random_state=666,
               noise={
                   'type': None,
                   'mean': None,
                   'stddev': None
               }):
    """Creates fake image with Gaussian sources.

    Creates a fake image with gaussian sources, whose parameters can be
    adjusted based on the following arguments.

    A background with spatial fluctuations at various scales is
    created seperately. This is achived by first creating the desired 2D power
    spectrum, which is a radial power law in Fourier space. According to
    litrature, the index of ISM power law distribution is -2.9. Taking the
    inverse FFT of this p_law array gives a background with the desired levels
    of spatial fluctuations in real space.

        Args:
            n_sources(int):       Number of sources
            shape(2-tuple):       Dimensions of the image
            amplitude_r(list):    Range of amplitudes of sources
            std_dev(list):        Range of standard deviations of sources
            random_state(int):    Seed for random number generator
            noise(dictionary):    Parameters for noise
                (i)   type:       Gaussian or Poisson
                (ii)  mean:       Mean value of noise
                (iii) stddev:     Standard deviation of gaussian noise
    """

    param_ranges = [('amplitude', [amplitude_r[0], amplitude_r[1]]),
                    ('x_mean', [0, shape[1]]), ('y_mean', [0, shape[0]]),
                    ('x_stddev', [std_dev[0], std_dev[1]]),
                    ('y_stddev', [std_dev[0], std_dev[1]]),
                    ('theta', [0, np.pi])]
    param_ranges = OrderedDict(param_ranges)
    sources = make_random_models_table(n_sources,
                                       param_ranges,
                                       random_state=random_state)

    if noise['type'] is None:
        sources = make_gaussian_sources_image(shape, sources)
    else:
        sources = sources + make_noise_image(shape,
                                             type=noise['type'],
                                             mean=noise['mean'],
                                             stddev=noise['stddev'])

    # CREATING BACKGROUNG (ISM)
    # The objective is to create a background with different levels of
    # spatial fluctuations built in. This is achived by first creating the
    # desired 2D power spectrum, which is a radial power law in Fourier space.
    # According to litrature, the index of ISM power law distribution is -2.9
    # Taking the inverse FFT of this p_law array gives a background with the
    # desired levels of spatial fluctuations in real space.

    p_law = np.zeros(shape, dtype=float)
    y, x = np.indices(p_law.shape)
    center = np.array([(y.max() - y.min()) / 2.0, (x.max() - x.min()) / 2.0])
    r = np.hypot(x - center[1], y - center[0])

    r_ind = r.astype(int)
    r_max = r.max().astype(int)

    a = np.arange(0.1, r_max + 1.1, 1)  # These values control size of clouds
    b = 10**11 * a**(-2.9)  # This controls magnitude of background

    for i in range(0, r_max + 1):
        p_law[r_ind > i] = b[i]

    magnitude = np.sqrt(p_law)
    phase = 2 * np.pi * np.random.randn(shape[0], shape[1])
    FFT = magnitude * np.exp(1j * phase)
    background = np.abs((fftpack.ifft2(fftpack.fftshift(FFT))))

    sim_sky = sources + background

    return sources, background, sim_sky
Пример #25
0
def make_gaia(coords,
              image=os.path.join('.', 'synthetic_gaia.fits'),
              epoch="J2020.5"):
    """
    Creates a synthetic image from GAIA DR2 photometry along the specified coordinates.

    Returns the synthetic image in fits format.

    Parameters:
    coords: Coordinates of centre of image.
    image: File name of image. Default is synthetic_gaia.fits
    epoch: Epoch to translate image. Default is J2020.5
    """
    #####
    ##### Define GMOS parameters
    ##### GMOS FoV is 330 arcsec
    ##### GMOS slit length is 330 arcsec
    ##### GMOS fwhm chosen in 0.3 arcsec
    ##### Image created is 390 arcsec, to accomadte additional overlays
    ##### GMOS read noise is 3.96  (e-/ADU)
    ##### GMOS gain is 1.829  (e- rms)
    #####

    gmosfov = 390 * u.arcsec
    fwhm = 0.3 * u.arcsec
    shape = (1300, 1300)
    zeroarr = np.zeros(shape)
    width = 390 * u.arcsec
    height = 390 * u.arcsec

    ##### Read coordinates and epoch
    coords = coords
    epoch = Time(epoch, format='jyear_str')

    ##### Query GAIA DR2 using astroquery TAP+
    ##### Synchronous query, limit of 2000 rows
    print('Searching GAIA TAP+ for stars over the GMOS FoV...')
    gaiasearch = Gaia.cone_search_async(coordinate=coords,
                                        radius=gmosfov,
                                        verbose=False)
    searchresults = gaiasearch.get_results()
    nstars = len(searchresults)
    print(nstars, 'stars recovered from GAIA TAP+ query over the GMOS FoV')
    if nstars == 2000:
        warnings.warn(
            'Asynchronous TAP+ service query limit reached, image is incomplete.'
        )

    fitshdr = mkfitshdr(coords, zeroarr, image, epoch)
    hdr = fitshdr[0]
    hdu = fitshdr[1]
    hdul = fitshdr[2]
    w = fitshdr[3]

    c = SkyCoord(ra=searchresults['ra'],
                 dec=searchresults['dec'],
                 pm_ra_cosdec=searchresults['pmra'],
                 pm_dec=searchresults['pmdec'],
                 obstime=Time(searchresults['ref_epoch'],
                              format='decimalyear'))

    cnew = c
    ###### in the current implementation, transformation of the image to the epoch is not applied

    ######    cnew = c.apply_space_motion(new_obstime=Time(epoch))
    star_coords = w.wcs_world2pix([cnew.ra.deg], [cnew.dec.deg], 0)

    xvalue = star_coords[0].ravel()
    yvalue = star_coords[1].ravel()
    flux = (searchresults['phot_g_mean_flux'] * u.mag).value

    ##### Error values
    cerr = SkyCoord(ra=searchresults['ra_error'],
                    dec=searchresults['dec_error'])

    xerrvalue = cerr.ra.value
    yerrvalue = cerr.dec.value

    xerrmask = np.nan_to_num(xerrvalue, nan=0.0, posinf=0.0, neginf=0.0)
    yerrmask = np.nan_to_num(yerrvalue, nan=0.0, posinf=0.0, neginf=0.0)
    xerrmask[xerrmask < 1.0] = 1.0
    yerrmask[yerrmask < 1.0] = 1.0
    ##### Error values less than 1.0 lead to incorrect values in photutils. Error values of 1.0 lead to no significiant differences in images compared to no error.

    ##### Create Table of results

    t = Table([flux, xvalue, yvalue, xerrmask, yerrmask],
              names=('flux', 'x_mean', 'y_mean', 'x_stddev', 'y_stddev'),
              dtype=('i8', 'i8', 'i8', 'i8', 'i8'))
    print('Table of stars is being generated as an image')
    zeroarr = make_gaussian_sources_image(shape, t)

    ##### Read noise

    read_noise = np.random.normal(scale=(3.92 / 1.829), size=shape)
    noise_image = make_noise_image(shape, distribution='poisson', mean=0.5)
    #####

    synth_image = zeroarr + noise_image
    #####
    ###### read_noise is disabled
    hdu = fits.PrimaryHDU(synth_image, header=hdr)
    hdul = fits.HDUList([hdu])
    hdul.writeto(image, overwrite=True)
    print('Synthetic GAIA DR2 image is saved as', image)
    return image
Пример #26
0
def generate_fits(tmpdir_factory):

    tmpdir = tmpdir_factory.mktemp("nm_map")
    filename = str(tmpdir.join("map.fits"))
    # Larger map to perform check_SNR

    np.random.seed(0)

    shape = (256, 256)
    pixsize = 1 / 3 * u.deg
    peak_flux = 1 * u.Jy
    noise_level = 0.1 * u.Jy / u.beam
    fwhm = 1 * u.deg
    nsources = 1

    wcs = WCS()
    wcs.wcs.crpix = np.asarray(shape) / 2 - 0.5  # Center of pixel
    wcs.wcs.cdelt = np.asarray([-1, 1]) * pixsize
    wcs.wcs.ctype = ("RA---TAN", "DEC--TAN")

    xx, yy = np.indices(shape)
    mask = np.sqrt((xx - (shape[1] - 1) / 2)**2 +
                   (yy - (shape[0] - 1) / 2)**2) > shape[0] / 2

    sources = Table(masked=True)
    sources["amplitude"] = np.ones(nsources) * peak_flux
    sources["x_mean"] = [shape[1] / 2]
    sources["y_mean"] = [shape[0] / 2]

    beam_std_pix = (fwhm / pixsize).decompose().value * gaussian_fwhm_to_sigma
    sources["x_stddev"] = np.ones(nsources) * beam_std_pix
    sources["y_stddev"] = np.ones(nsources) * beam_std_pix
    sources["theta"] = np.zeros(nsources)

    data = make_gaussian_sources_image(shape, sources)

    hits = np.ones(shape=shape, dtype=np.float)
    uncertainty = np.ones(shape, dtype=np.float) * noise_level.to(
        u.Jy / u.beam).value
    data += np.random.normal(loc=0, scale=1, size=shape) * uncertainty
    data[mask] = np.nan
    hits[mask] = 0
    uncertainty[mask] = 0

    header = wcs.to_header()
    header["UNIT"] = "Jy / beam", "Fake Unit"

    primary_header = fits.header.Header()
    primary_header["f_sampli"] = 10.0, "Fake the f_sampli keyword"
    primary_header["FWHM_260"] = fwhm.to(
        u.arcsec).value, "[arcsec] Fake the FWHM_260 keyword"
    primary_header["FWHM_150"] = fwhm.to(
        u.arcsec).value, "[arcsec] Fake the FWHM_150 keyword"

    primary_header["nsources"] = 1, "Number of fake sources"
    primary_header["noise"] = noise_level.to(
        u.Jy / u.beam).value, "[Jy/beam] noise level per map"

    primary = fits.hdu.PrimaryHDU(header=primary_header)

    hdus = fits.hdu.HDUList(hdus=[primary])
    for band in ["1mm", "2mm"]:
        hdus.append(
            fits.hdu.ImageHDU(data,
                              header=header,
                              name="Brightness_{}".format(band)))
        hdus.append(
            fits.hdu.ImageHDU(uncertainty,
                              header=header,
                              name="Stddev_{}".format(band)))
        hdus.append(
            fits.hdu.ImageHDU(hits,
                              header=header,
                              name="Nhits_{}".format(band)))
        hdus.append(fits.hdu.BinTableHDU(sources, name="fake_sources"))

    hdus.writeto(filename, overwrite=True)

    return filename
Пример #27
0
def generate_nikamaps(
    tmpdir_factory,
    shape=(61, 61),
    pixsize=1 / 3 * u.deg,
    noise_level=1 * Jybeam,
    nmaps=10,
    nsources=5,
    fwhm=1 * u.deg,
    nrots=4,
):
    # Generate several maps with sources and noise... only one band...

    tmpdir = tmpdir_factory.mktemp("nm_maps")

    wcs = WCS()
    wcs.wcs.crpix = np.asarray(shape) / 2 - 0.5  # Center of pixel
    wcs.wcs.cdelt = np.asarray([-1, 1]) * pixsize
    wcs.wcs.ctype = ("RA---TAN", "DEC--TAN")

    # Fake sources for all maps
    np.random.seed(0)

    sources = Table(masked=True)
    sources["amplitude"] = np.random.uniform(1, 10, size=nsources) * u.Jy
    sources["x_mean"] = np.random.uniform(1 / 4, 3 / 4,
                                          size=nsources) * shape[1]
    sources["y_mean"] = np.random.uniform(1 / 4, 3 / 4,
                                          size=nsources) * shape[0]

    beam_std_pix = (fwhm / pixsize).decompose().value * gaussian_fwhm_to_sigma
    sources["x_stddev"] = np.ones(nsources) * beam_std_pix
    sources["y_stddev"] = np.ones(nsources) * beam_std_pix
    sources["theta"] = np.zeros(nsources)

    data_sources = make_gaussian_sources_image(shape, sources) * u.Jy / u.beam

    a, d = wcs.wcs_pix2world(sources["x_mean"], sources["y_mean"], 0)
    sources.add_columns(
        [Column(a * u.deg, name="ra"),
         Column(d * u.deg, name="dec")])
    sources.remove_columns(
        ["x_mean", "y_mean", "x_stddev", "y_stddev", "theta"])
    sources.sort("amplitude")
    sources.reverse()
    sources.add_column(Column(np.arange(len(sources)), name="ID"), 0)

    # Elliptical gaussian mask
    def elliptical_mask_rot(shape, sigma, theta, limit):
        xx, yy = np.indices(shape)

        xx_arr = xx - (shape[1] - 1) / 2
        yy_arr = yy - (shape[0] - 1) / 2

        c, s = np.cos(theta), np.sin(theta)
        rot = np.array(((c, -s), (s, c)))

        xx_arr, yy_arr = np.dot(rot, [xx_arr.flatten(), yy_arr.flatten()])

        xx_arr = (xx_arr.reshape(shape) / (2 * sigma[1]**2))**2
        yy_arr = (yy_arr.reshape(shape) / (2 * sigma[0]**2))**2

        mask = np.sqrt(xx_arr + yy_arr) > limit
        return mask

    #  mask = mask_rot(shape, (np.sqrt(0.5), np.sqrt(0.5)), 0, (shape[0] - 1) / 2)

    primary_header = fits.header.Header()
    primary_header["f_sampli"] = 10.0, "Fake the f_sampli keyword"
    primary_header["FWHM_260"] = (
        fwhm.to(u.arcsec).value,
        "[arcsec] Fake the FWHM_260 keyword",
    )
    primary_header["FWHM_150"] = (
        fwhm.to(u.arcsec).value,
        "[arcsec] Fake the FWHM_150 keyword",
    )

    primary_header["nsources"] = nsources, "Number of fake sources"
    primary_header["pixsize"] = pixsize.to(u.deg).value, "[deg] pixel size"
    primary_header["nmaps"] = nmaps, "number of maps produced"
    primary_header["nrots"] = nmaps, "number of rotations"
    primary_header["shape0"] = shape[0], "[0] of map shape"
    primary_header["shape1"] = shape[1], "[1] of map shape"
    primary_header["noise"] = (
        noise_level.to(u.Jy / u.beam).value,
        "[Jy/beam] noise level per map",
    )

    primary = fits.hdu.PrimaryHDU(header=primary_header)

    filenames = []

    for i_map in range(nmaps):

        # Rotated asymetric mask
        mask = elliptical_mask_rot(
            shape,
            (np.sqrt(1 / 2), np.sqrt(2 / 5)),
            i_map * np.pi / nrots,
            (shape[0] - 1) / 2,
        )

        filename = str(tmpdir.join("map_{}.fits".format(i_map)))

        hits = np.ones(shape=shape, dtype=np.float)
        uncertainty = np.ones(shape=shape, dtype=np.float) * noise_level
        data = np.random.normal(loc=0, scale=1, size=shape) * uncertainty

        data += data_sources
        data[mask] = 0
        hits[mask] = 0
        uncertainty[mask] = 0

        header = wcs.to_header()
        header["UNIT"] = "Jy / beam", "Fake Unit"

        hdus = fits.hdu.HDUList(hdus=[primary])

        for band in ["1mm", "2mm"]:
            hdus.append(
                fits.hdu.ImageHDU(data.value,
                                  header=header,
                                  name="Brightness_{}".format(band)))
            hdus.append(
                fits.hdu.ImageHDU(uncertainty.value,
                                  header=header,
                                  name="Stddev_{}".format(band)))
            hdus.append(
                fits.hdu.ImageHDU(hits,
                                  header=header,
                                  name="Nhits_{}".format(band)))
            hdus.append(fits.hdu.BinTableHDU(sources, name="fake_sources"))

        hdus.writeto(filename, overwrite=True)

        filenames.append(filename)

    return filenames
Пример #28
0
from astropy.table import Table
from photutils.datasets import make_gaussian_sources_image
from photutils.datasets import make_noise_image
from astropy.io import fits

nstar = 400
sigma_psf = 2.0
shape = (500, 500)
noise_mean = 5.0
np.random.seed(1000)
# make a table of Gaussian sources
table = Table()
table['flux'] = 1000 - 1000 * np.random.power(2.35, size=nstar)
table['x_mean'] = np.random.randint(0, high=shape[1] - 1, size=nstar)
table['y_mean'] = np.random.randint(0, high=shape[0] - 1, size=nstar)
table['x_stddev'] = sigma_psf * np.ones(nstar)
table['y_stddev'] = table['x_stddev']
table['theta'] = np.radians(np.zeros(nstar))

# make an image of the sources with Poisson noise
image1 = make_gaussian_sources_image(shape, table)
image2 = image1 + make_noise_image(
    shape, distribution='poisson', mean=noise_mean)

fig = plt.figure(figsize=(10, 10))
plt.imshow(image2, origin='lower', interpolation='nearest', cmap='gray')
plt.savefig('image.jpg')

hdu = fits.PrimaryHDU(image2)
hdu.writeto('image.fits', overwrite=True)
Пример #29
0
def test_detection(StarFinder_Algorithm, sigma_psf, amplitude, PSF_size=1):
    '''create an image with mock sources and try to detect them
    
    Parameters
    ----------
        
    StarFinder_Algorithm:
         Class to detect stars
    
    sigma_psf:
        standard deviation of the PSF of the mock sources 
    
    amplitude:
        amplitude of the mock sources
        
    PSF_size: 
        The StarFinder_Algorithm need to know the sigma of the sources
        they try to detect. This parameter changes the provided size 
        compared to the sigma of the mock sources.
    '''

    # create mock data
    n_sources = 20
    tshape = (256, 256)

    param_ranges = OrderedDict([('amplitude', [amplitude, amplitude * 1.2]),
                                ('x_mean', [0, tshape[0]]),
                                ('y_mean', [0, tshape[1]]),
                                ('x_stddev', [sigma_psf, sigma_psf]),
                                ('y_stddev', [sigma_psf, sigma_psf]),
                                ('theta', [0, 0])])

    sources = make_random_gaussians_table(n_sources,
                                          param_ranges,
                                          random_state=1234)

    image = (make_gaussian_sources_image(tshape, sources) + make_noise_image(
        tshape, type='poisson', mean=6., random_state=1) + make_noise_image(
            tshape, type='gaussian', mean=0., stddev=2., random_state=34234))

    fwhm = gaussian_sigma_to_fwhm * sigma_psf

    mean, median, std = sigma_clipped_stats(image, sigma=3.0)

    StarFinder = StarFinder_Algorithm(fwhm=fwhm * PSF_size,
                                      threshold=3. * std,
                                      sharplo=0.1,
                                      sharphi=1.0,
                                      roundlo=-.2,
                                      roundhi=.2)

    sources_mock = StarFinder(image)

    # for consistent table output
    for col in sources_mock.colnames:
        sources_mock[col].info.format = '%.8g'

    string = str(StarFinder_Algorithm).split(
        '.')[-1][:-2] + f' sig={sigma_psf} A={amplitude}'
    print(f'{string}: {len(sources_mock):} of {n_sources} sources found')

    positions = np.transpose(
        [sources_mock['xcentroid'], sources_mock['ycentroid']])
    apertures = CircularAperture(positions, r=fwhm)

    return image, apertures, sources, string