Example #1
0
def test__convolution_inputs():
    m1 = Const2D()
    m2 = Const2D()

    model = convolve_models_fft(m1, m2, ((-1, 1), (-1, 1)), 0.01)

    x = np.arange(-1, 1, 0.1)
    y = np.arange(-2, 2, 0.1)
    grid0 = np.meshgrid(x, x)
    grid1 = np.meshgrid(y, y)

    # scalar inputs
    assert (np.array([1]), (1, )) == model._convolution_inputs(1)

    # Multiple inputs
    assert np.all(
        model._convolution_inputs(
            *grid0)[0] == np.reshape([grid0[0], grid0[1]], (2, -1)).T)
    assert model._convolution_inputs(*grid0)[1] == grid0[0].shape
    assert np.all(
        model._convolution_inputs(
            *grid1)[0] == np.reshape([grid1[0], grid1[1]], (2, -1)).T)
    assert model._convolution_inputs(*grid1)[1] == grid1[0].shape

    # Error
    with pytest.raises(ValueError) as err:
        model._convolution_inputs(grid0[0], grid1[1])
    assert str(err.value) ==\
        "Values have differing shapes"
Example #2
0
    def evaluate(x, y, constant, amplitude, x_mean, y_mean, x_stddev, y_stddev,
                 theta):
        """Two dimensional Gaussian plus constant function."""

        model = Const2D(constant)(x, y) + Gaussian2D(
            amplitude, x_mean, y_mean, x_stddev, y_stddev, theta)(x, y)
        return model
def _fit_2dgaussian(data):
    """
    Fit a 2d Gaussian to data.

    Written as a replace for functionality that was removed from
    photutils.

    Keep this private so we don't have to support it....

    Copy/pasted from
    https://github.com/astropy/photutils/pull/1064/files#diff-9e64908ff7ac552845b4831870a749f397d73c681d218267bd9087c7757e6dd4R285
    """
    props = data_properties(data - np.min(data))

    init_const = 0.  # subtracted data minimum above
    init_amplitude = np.ptp(data)

    g_init = (Const2D(init_const) +
              Gaussian2D(amplitude=init_amplitude,
                         x_mean=props.xcentroid,
                         y_mean=props.ycentroid,
                         x_stddev=props.semimajor_sigma.value,
                         y_stddev=props.semiminor_sigma.value,
                         theta=props.orientation.value))

    fitter = LevMarLSQFitter()
    y, x = np.indices(data.shape)
    gfit = fitter(g_init, x, y, data)

    return gfit
def make_one_donut(center, diameter=10, amplitude=0.25):
    sigma = diameter / 2
    mh = RickerWavelet2D(amplitude=amplitude,
                      x_0=center[0], y_0=center[1],
                      sigma=sigma)
    gauss = Gaussian2D(amplitude=amplitude,
                       x_mean=center[0], y_mean=center[1],
                       x_stddev=sigma, y_stddev=sigma)
    return Const2D(amplitude=1) + (mh - gauss)
Example #5
0
def test_input_shape_2d():
    m1 = Const2D()
    m2 = Const2D()

    model = convolve_models_fft(m1, m2, ((-1, 1), (-1, 1)), 0.01)

    results = model(0, 0)
    assert results.shape == (1, )

    x = np.arange(-1, 1, 0.1)
    results = model(x, 0)
    assert results.shape == x.shape
    results = model(0, x)
    assert results.shape == x.shape

    grid = np.meshgrid(x, x)
    results = model(*grid)
    assert results.shape == grid[0].shape
    assert results.shape == grid[1].shape
def twoD_gaussian(shape=(201, 201), x_std=10., y_std=10., theta=0, amp=1.,
                  bkg=0.):

    centre = tuple([val // 2 for val in shape])

    mod = Gaussian2D(x_mean=centre[0], y_mean=centre[1],
                     x_stddev=x_std, y_stddev=y_std,
                     amplitude=amp, theta=theta) + \
        Const2D(amplitude=bkg)

    return mod
Example #7
0
File: fji.py Project: felipeji/fji
def FWHM(data, xc, yc):
    from astropy.modeling.models import Gaussian2D
    from astropy.modeling.models import Const2D

    from astropy.modeling.fitting import LevMarLSQFitter

    # Data:
    x, y = np.mgrid[:data.shape[1], :data.shape[0]]

    # Model:
    cte0 = np.nanmean(data)
    Cte = Const2D(cte0)

    Gauss = Gaussian2D(amplitude=data[int(yc), int(xc)], x_mean=xc, y_mean=yc)
    # Parametros fijos
    Gauss.x_mean.fixed = True
    Gauss.y_mean.fixed = True

    model = Gauss + Cte

    # Parametros ligados: imponemos que sea una gaussiana redonda
    def tie(model):
        return model.y_stddev_0

    model.x_stddev_0.tied = tie

    # Fit
    fitter = LevMarLSQFitter()
    import warnings
    with warnings.catch_warnings():
        # Ignore model linearity warning from the fitter
        warnings.simplefilter('ignore')
        fit = fitter(model, x, y, data)

    sigma = fit.x_stddev_0.value

    FWHM = 2.3548 * sigma

    return FWHM
def make_one_donut(center, diameter=10, amplitude=0.25):
    '''
    This fuction is pretty eavy, it uses 3 mathematical fuction creates the
    image of a single donut to by added to the flat image

    Parameters
    ----------

    center : numpy array
        center[0] : the position along the x axis of the center of the donut
        center[1] : the position along the y axis of the center of the donut

    diameter : int, float
        Can be interpreted as the diameter in pixel of the donut.
        In reality it is 2sigma of the Gaussian and RickerWavelet (ex MexicaHat)
        functions used to simulate the donut

    amplitude : float, optional
        The peak intensity of the aforementioned functions

    Output
    ------

    Const2D(amplitude=1) + (mh - gauss) : numpy array
        It is a image of the donut created 
    '''
    log.info(hist())

    sigma = diameter / 2
    mh = RickerWavelet2D(amplitude=amplitude,
                         x_0=center[0],
                         y_0=center[1],
                         sigma=sigma)
    gauss = Gaussian2D(amplitude=amplitude,
                       x_mean=center[0],
                       y_mean=center[1],
                       x_stddev=sigma,
                       y_stddev=sigma)
    return Const2D(amplitude=1) + (mh - gauss)
Example #9
0
def centroid_2dg(data, error=None, mask=None):
    """
    Calculate the centroid of a 2D array by fitting a 2D Gaussian (plus
    a constant) to the array.

    Non-finite values (e.g., NaN or inf) in the ``data`` or ``error``
    arrays are automatically masked. These masks are combined.

    Parameters
    ----------
    data : array_like
        The 2D data array.

    error : array_like, optional
        The 2D array of the 1-sigma errors of the input ``data``.

    mask : array_like (bool), optional
        A boolean mask, with the same shape as ``data``, where a `True`
        value indicates the corresponding element of ``data`` is masked.

    Returns
    -------
    centroid : `~numpy.ndarray`
        The ``x, y`` coordinates of the centroid.
    """
    from ..morphology import data_properties  # prevent circular imports

    data = np.ma.asanyarray(data)

    if mask is not None and mask is not np.ma.nomask:
        mask = np.asanyarray(mask)
        if data.shape != mask.shape:
            raise ValueError('data and mask must have the same shape.')
        data.mask |= mask

    if np.any(~np.isfinite(data)):
        data = np.ma.masked_invalid(data)
        warnings.warn('Input data contains non-finite values (e.g., NaN or '
                      'infs) that were automatically masked.',
                      AstropyUserWarning)

    if error is not None:
        error = np.ma.masked_invalid(error)
        if data.shape != error.shape:
            raise ValueError('data and error must have the same shape.')
        data.mask |= error.mask
        weights = 1.0 / error.clip(min=1.e-30)
    else:
        weights = np.ones(data.shape)

    if np.ma.count(data) < 7:
        raise ValueError('Input data must have a least 7 unmasked values to '
                         'fit a 2D Gaussian plus a constant.')

    # assign zero weight to masked pixels
    if data.mask is not np.ma.nomask:
        weights[data.mask] = 0.

    mask = data.mask
    data.fill_value = 0.
    data = data.filled()

    # Subtract the minimum of the data as a rough background estimate.
    # This will also make the data values positive, preventing issues with
    # the moment estimation in data_properties. Moments from negative data
    # values can yield undefined Gaussian parameters, e.g., x/y_stddev.
    props = data_properties(data - np.min(data), mask=mask)

    constant_init = 0.  # subtracted data minimum above
    g_init = (Const2D(constant_init)
              + Gaussian2D(amplitude=np.ptp(data),
                           x_mean=props.xcentroid.value,
                           y_mean=props.ycentroid.value,
                           x_stddev=props.semimajor_axis_sigma.value,
                           y_stddev=props.semiminor_axis_sigma.value,
                           theta=props.orientation.value))
    fitter = LevMarLSQFitter()
    y, x = np.indices(data.shape)
    gfit = fitter(g_init, x, y, data, weights=weights)
    return np.array([gfit.x_mean_1.value, gfit.y_mean_1.value])
Example #10
0
def prepare_psf_model(psfmodel,
                      xname=None,
                      yname=None,
                      fluxname=None,
                      renormalize_psf=True):
    """
    Convert a 2D PSF model to one suitable for use with
    `BasicPSFPhotometry` or its subclasses.

    .. note::

        This function is needed only in special cases where the PSF
        model does not have ``x_0``, ``y_0``, and ``flux`` model
        parameters. In particular, it is not needed for any of the PSF
        models provided by photutils (e.g., `~photutils.psf.EPSFModel`,
        `~photutils.psf.IntegratedGaussianPRF`,
        `~photutils.psf.FittableImageModel`,
        `~photutils.psf.GriddedPSFModel`, etc).

    Parameters
    ----------
    psfmodel : `~astropy.modeling.Fittable2DModel`
        The model to assume as representative of the PSF.

    xname : `str` or `None`, optional
        The name of the ``psfmodel`` parameter that corresponds to the
        x-axis center of the PSF. If `None`, the model will be assumed
        to be centered at x=0, and a new parameter will be added for the
        offset.

    yname : `str` or `None`, optional
        The name of the ``psfmodel`` parameter that corresponds to the
        y-axis center of the PSF. If `None`, the model will be assumed
        to be centered at y=0, and a new parameter will be added for the
        offset.

    fluxname : `str` or `None`, optional
        The name of the ``psfmodel`` parameter that corresponds to the
        total flux of the star. If `None`, a scaling factor will be
        added to the model.

    renormalize_psf : bool, optional
        If `True`, the model will be integrated from -inf to inf and
        rescaled so that the total integrates to 1. Note that this
        renormalization only occurs *once*, so if the total flux of
        ``psfmodel`` depends on position, this will *not* be correct.

    Returns
    -------
    result : `~astropy.modeling.Fittable2DModel`
        A new model ready to be passed into `BasicPSFPhotometry` or its
        subclasses.
    """
    if xname is None:
        xinmod = _InverseShift(0, name='x_offset')
        xname = 'offset_0'
    else:
        xinmod = Identity(1)
        xname = xname + '_2'
    xinmod.fittable = True

    if yname is None:
        yinmod = _InverseShift(0, name='y_offset')
        yname = 'offset_1'
    else:
        yinmod = Identity(1)
        yname = yname + '_2'
    yinmod.fittable = True

    outmod = (xinmod & yinmod) | psfmodel.copy()

    if fluxname is None:
        outmod = outmod * Const2D(1, name='flux_scaling')
        fluxname = 'amplitude_3'
    else:
        fluxname = fluxname + '_2'

    if renormalize_psf:
        # we do the import here because other machinery works w/o scipy
        from scipy import integrate

        integrand = integrate.dblquad(psfmodel, -np.inf, np.inf,
                                      lambda x: -np.inf, lambda x: np.inf)[0]
        normmod = Const2D(1. / integrand, name='renormalize_scaling')
        outmod = outmod * normmod

    # final setup of the output model - fix all the non-offset/scale
    # parameters
    for pnm in outmod.param_names:
        outmod.fixed[pnm] = pnm not in (xname, yname, fluxname)

    # and set the names so that BasicPSFPhotometry knows what to do
    outmod.xname = xname
    outmod.yname = yname
    outmod.fluxname = fluxname

    # now some convenience aliases if reasonable
    outmod.psfmodel = outmod[2]
    if 'x_0' not in outmod.param_names and 'y_0' not in outmod.param_names:
        outmod.x_0 = getattr(outmod, xname)
        outmod.y_0 = getattr(outmod, yname)
    if 'flux' not in outmod.param_names:
        outmod.flux = getattr(outmod, fluxname)

    return outmod
Example #11
0
def make_images(psf_sigma):
    # Define width of the source and the PSF
    source_sigma = 4
    sigma = np.sqrt(psf_sigma**2 + source_sigma**2)
    amplitude = 1E3 / (2 * np.pi * sigma**2)

    source = Gaussian2D(amplitude, 99, 99, sigma, sigma)
    background = Const2D(1)
    model = source + background

    # Define data shape
    shape = (200, 200)
    y, x = np.indices(shape)

    # Create a new WCS object
    wcs = WCS(naxis=2)

    # Set up an Galactic projection
    wcs.wcs.crpix = [100.5, 100.5]
    wcs.wcs.cdelt = np.array([0.02, 0.02])
    wcs.wcs.crval = [0, 0]
    wcs.wcs.ctype = ['GLON-CAR', 'GLAT-CAR']

    # Fake data
    random_state = get_random_state(0)
    data = random_state.poisson(model(x, y))

    # Create exclusion mask
    center = SkyCoord(0, 0, frame='galactic', unit='deg')
    circle = CircleSkyRegion(center, 0.5 * u.deg)
    exclusion = SkyImage(data=x, wcs=wcs).region_mask(circle)

    # Save data
    header = wcs.to_header()

    mask = ~exclusion.data
    hdu = fits.PrimaryHDU(data=mask.astype('int32'), header=header)
    filename = 'exclusion.fits.gz'
    print('Writing {}'.format(filename))
    hdu.writeto(filename, clobber=True)

    hdu = fits.PrimaryHDU(data=data.astype('int32'), header=header)
    filename = 'counts.fits.gz'
    print('Writing {}'.format(filename))
    hdu.writeto(filename, clobber=True)

    hdu = fits.PrimaryHDU(data=model(x, y).astype('float32'), header=header)
    filename = 'model.fits.gz'
    print('Writing {}'.format(filename))
    hdu.writeto(filename, clobber=True)

    hdu = fits.PrimaryHDU(data=background(x, y).astype('float32'),
                          header=header)
    filename = 'background.fits.gz'
    print('Writing {}'.format(filename))
    hdu.writeto(filename, clobber=True)

    hdu = fits.PrimaryHDU(data=source(x, y).astype('float32'), header=header)
    filename = 'source.fits.gz'
    print('Writing {}'.format(filename))
    hdu.writeto(filename, clobber=True)

    exposure = 1E12 * np.ones(shape)
    hdu = fits.PrimaryHDU(data=exposure.astype('float32'), header=header)
    filename = 'exposure.fits.gz'
    print('Writing {}'.format(filename))
    hdu.writeto(filename, clobber=True)
Example #12
0
from __future__ import print_function, division
import numpy as np

from astropy.modeling.models import Gaussian2D, Const2D
from astropy.io import fits
from astropy.wcs import WCS

from gammapy.utils.random import get_random_state

# Define width of the source and the PSF
sigma_psf, sigma_source = 3, 4
sigma = np.sqrt(sigma_psf**2 + sigma_source**2)
amplitude = 1E3 / (2 * np.pi * sigma**2)

source = Gaussian2D(amplitude, 99, 99, sigma, sigma)
background = Const2D(1)
model = source + background

# Define data shape
shape = (200, 200)
y, x = np.indices(shape)

# Create a new WCS object
w = WCS(naxis=2)

# Set up an Galactic projection
w.wcs.crpix = [99, 99]
w.wcs.cdelt = np.array([0.02, 0.02])
w.wcs.crval = [0, 0]
w.wcs.ctype = ['GLON-CAR', 'GLAT-CAR']