Esempio n. 1
0
def test_Sersic2D_theta():
    theta = Angle(90, 'deg')
    model1 = models.Sersic2D(1, 5, 4, 25, 25, 0.5, theta=theta)

    theta2 = np.pi / 2.
    model2 = models.Sersic2D(1, 5, 4, 25, 25, 0.5, theta=theta2)

    assert model1.theta.quantity.to('radian').value == model2.theta.value

    assert model1(619.42, 31.314) == model2(619.42, 31.314)
Esempio n. 2
0
def plot_model(image,model_morph):  
  ny, nx = image.shape
  imy, imx = np.mgrid[0:ny, 0:nx]


  sersic_model = models.Sersic2D(
    amplitude=model_morph.sersic_amplitude,
    r_eff=model_morph.sersic_rhalf,
    n=model_morph.sersic_n,
    x_0=model_morph.sersic_xc,
    y_0=model_morph.sersic_yc,
    ellip=model_morph.sersic_ellip,
    theta=model_morph.sersic_theta)
    
  fitted_model = sersic_model(imx, imy)
  plt.subplot(121)
  plt.imshow(image, cmap='rainbow', origin='lower',
           norm=simple_norm(image, stretch='log', log_a=10000))
  plt.subplot(122)
  plt.imshow(fitted_model, cmap='rainbow', origin='lower',
           norm=simple_norm(image, stretch='log', log_a=10000))
  plt.show()

  plt.imshow(image-fitted_model, cmap='rainbow', origin='lower')
  plt.colorbar()
  plt.show()
  plt.hist((image-fitted_model).flatten(),bins=25)
  plt.show()
Esempio n. 3
0
def test_print_special_operator_CompoundModel(capsys):
    """
    Test that issue #11310 has been fixed
    """

    model = convolve_models(models.Sersic2D(), models.Gaussian2D())
    print(model)

    true_out = "Model: CompoundModel\n" +\
               "Inputs: ('x', 'y')\n" +\
               "Outputs: ('z',)\n" +\
               "Model set size: 1\n" +\
               "Expression: convolve_fft (([0]), ([1]))\n" +\
               "Components: \n" +\
               "    [0]: <Sersic2D(amplitude=1., r_eff=1., n=4., x_0=0., y_0=0., ellip=0., theta=0.)>\n" +\
               "\n" +\
               "    [1]: <Gaussian2D(amplitude=1., x_mean=0., y_mean=0., x_stddev=1., y_stddev=1., theta=0.)>\n" +\
               "Parameters:\n" +\
               "    amplitude_0 r_eff_0 n_0 x_0_0 y_0_0 ... y_mean_1 x_stddev_1 y_stddev_1 theta_1\n" +\
               "    ----------- ------- --- ----- ----- ... -------- ---------- ---------- -------\n" +\
               "            1.0     1.0 4.0   0.0   0.0 ...      0.0        1.0        1.0     0.0\n"

    out, err = capsys.readouterr()
    assert err == ''
    assert out == true_out
Esempio n. 4
0
def test_convolved_sersic():
    from scipy.signal import fftconvolve
    # Create Gaussian PSF.
    size = 10  # on each side from the center
    sigma_psf = 2.0
    y, x = np.mgrid[-size:size + 1, -size:size + 1]
    psf = np.exp(-(x**2 + y**2) / (2.0 * sigma_psf**2))
    psf /= np.sum(psf)
    # Create 2D Sersic profile.
    ny, nx = 25, 25
    y, x = np.mgrid[0:ny, 0:nx]
    sersic = models.Sersic2D(amplitude=1,
                             r_eff=5,
                             n=1.5,
                             x_0=12,
                             y_0=12,
                             ellip=0.5,
                             theta=0)
    z = sersic(x, y)
    # Create "convolved" Sersic profile with same properties as normal one.
    convolved_sersic = statmorph.ConvolvedSersic2D(amplitude=1,
                                                   r_eff=5,
                                                   n=1.5,
                                                   x_0=12,
                                                   y_0=12,
                                                   ellip=0.5,
                                                   theta=0)
    with pytest.raises(AssertionError):
        _ = convolved_sersic(x, y)  # PSF not set yet
    convolved_sersic.set_psf(psf)
    z_convolved = convolved_sersic(x, y)
    # Compare results.
    assert_allclose(z_convolved, fftconvolve(z, psf, mode='same'))
    def ellipsefit(self, plot=True, mode='sersic'):
        """ Fit cube with elliptical isophote

			Args:
				plot (bool): if 'True', make plots
				mode (str): method to use to do fit 
					('sersic' for Sersic fitting, 'isophote' for elliptical isophotes)

			Outputs:
				Re (float): half-light radius
		"""

        print('Fitting ellipse to white-light image...')

        if mode == 'sersic':
            # Fit with 2D Sersic profile
            y, x = np.mgrid[:self.ysize, :self.xsize]
            p_init = models.Sersic2D(amplitude=0.05,
                                     r_eff=25,
                                     n=4,
                                     x_0=25,
                                     y_0=43,
                                     ellip=0.5,
                                     theta=5)
            fit_p = fitting.LevMarLSQFitter()
            p = fit_p(p_init, x, y, self.bband)
            print(p)

            if plot:
                fig, axs = plt.subplots(nrows=1,
                                        ncols=2,
                                        figsize=(10, 5),
                                        sharex=True)
                axs[0].imshow(self.bband,
                              origin='lower',
                              cmap='viridis',
                              vmin=0,
                              vmax=13)
                axs[1].imshow(p(x, y),
                              origin='lower',
                              cmap='viridis',
                              vmin=0,
                              vmax=13)
                plt.show()

        # TODO: finish elliptical isophote fitting
        if mode == 'isophote':
            pass

        return
Esempio n. 6
0
def fit_sersic2d(image, ellip=0.5, theta=0, fixed={}):
    # Estimate center of target
    y_mean, x_mean = np.array(image.shape) // 2  # Center guess

    # Create model to fit
    model = models.Sersic2D(amplitude=image.max(),
                            r_eff=x_mean // 4,
                            n=2,
                            x_0=x_mean,
                            y_0=y_mean,
                            ellip=ellip,
                            theta=theta,
                            fixed=fixed)

    # Fit model to grid
    fitted_line, fit = fit_model(image, model)

    return fitted_line
Esempio n. 7
0
File: npl.py Progetto: gbrammer/wfc3
def demo():
    """
    Show test where the source count distribution is a grism model
    """
    import astropy.io.fits as pyfits
    
    flt = pyfits.open('id7h04dvq_GrismFLT.fits')
    flt = pyfits.open('id7h44toq_GrismFLT.fits')
    flt = pyfits.open('id7h01ovq_GrismFLT.fits')
    
    mask = (flt['GDQ'].data == 0) & (flt['GERR'].data < 0.1) & (flt['GERR'].data > 0)
    
    noise = np.random.normal(size=mask.sum())*np.median(flt['GERR'].data[mask])
    data = flt['MODEL'].data[mask] + noise
    
    R = np.arange(-10,10,1.e-4)
    noise = np.random.normal(size=R.size)*ss
    data = np.exp(-R**2/2/sig**2)**2 + noise
    
    from astropy.modeling import models
    n = 1
    r_e = 100
    ser = models.Sersic2D(amplitude=1, r_eff=r_e, n=n, x_0=500, y_0=500, ellip=0, theta=0)
    yp, xp = np.indices((1014,1014))
    ser_data = ser(xp, yp)
    
    ser_data /= ser_data.max()
    
    noise = np.random.normal(size=ser_data.shape)*ss
    
    data = (ser_data + noise).flatten()
    
    #data *= 100
    #data = noise
    
    import mywfc3.npl 
    self = mywfc3.npl.NoisyPowerlaw(data=data, c0=[0,0,0,0,-2])
    self.dx_min = 0
    x = np.arange(self.range[0], self.range[1], self.s0/50)
    res, fit = self.fit(x=x, tol=1.e-6)
    plt.plot(self.xh, self.yh, color='k', linestyle='steps-mid')
    plt.plot(self.xh, fit, color='r', linestyle='steps-mid')
    
    sn_mask =  (flt['MODEL'].data < 0.5*flt['GERR'].data)[mask]
Esempio n. 8
0
def test_print_special_operator_CompoundModel(capsys):
    """
    Test that issue #11310 has been fixed
    """

    model = convolve_models(models.Sersic2D(), models.Gaussian2D())
    with astropy.conf.set_temp('max_width', 80):
        assert str(model) == "Model: CompoundModel\n" +\
                             "Inputs: ('x', 'y')\n" +\
                             "Outputs: ('z',)\n" +\
                             "Model set size: 1\n" +\
                             "Expression: convolve_fft (([0]), ([1]))\n" +\
                             "Components: \n" +\
                             "    [0]: <Sersic2D(amplitude=1., r_eff=1., n=4., x_0=0., y_0=0., ellip=0., theta=0.)>\n" +\
                             "\n" +\
                             "    [1]: <Gaussian2D(amplitude=1., x_mean=0., y_mean=0., x_stddev=1., y_stddev=1., theta=0.)>\n" +\
                             "Parameters:\n" +\
                             "    amplitude_0 r_eff_0 n_0 x_0_0 y_0_0 ... y_mean_1 x_stddev_1 y_stddev_1 theta_1\n" +\
                             "    ----------- ------- --- ----- ----- ... -------- ---------- ---------- -------\n" +\
                             "            1.0     1.0 4.0   0.0   0.0 ...      0.0        1.0        1.0     0.0"
Esempio n. 9
0
def test_psf_convolved_image_model():
    """Test fitting and PSF convolution"""

    # Make model:

    imsize = 300

    sersic_model = models.Sersic2D(
        amplitude=1,
        r_eff=25,
        n=2,
        x_0=imsize / 2,
        y_0=imsize / 2,
        ellip=0,
        theta=0,
        bounds={
            'amplitude': (0., None),
            'r_eff': (0, None),
            'n': (0, 10),
            'ellip': (0, 1),
            'theta': (-2 * np.pi, 2 * np.pi),
        },
    )

    # Make model image
    image = model_to_image(sersic_model, imsize)

    # Make a PSF
    x_grid, y_grid = make_grid(51, factor=1)
    PSF = Moffat2D(x_0=25.0, y_0=25.0)(x_grid, y_grid)
    PSF /= PSF.sum()

    # Make a PSF image using model image and PSF
    psf_sersic_image = convolve(image, PSF)

    # Make a PSFConvolvedModel2D
    psf_sersic_model = PSFConvolvedModel2D(sersic_model,
                                           psf=PSF,
                                           oversample=None)
    psf_sersic_model.fixed['psf_pa'] = True

    # Make a PSFConvolvedModel2D image
    psf_sersic_model_image = model_to_image(psf_sersic_model, imsize)

    # Compare the PSF image to PSFConvolvedModel2D image
    error_arr = abs(psf_sersic_model_image -
                    psf_sersic_image) / psf_sersic_image
    assert np.max(error_arr) < 0.01  # max error less than 1% error

    # Test fitting

    # Change params with offset
    psf_sersic_model.r_eff = 23
    psf_sersic_model.x_0 = 0.6 + imsize / 2
    psf_sersic_model.y_0 = 0.1 + imsize / 2
    psf_sersic_model.n = 3

    # Fit
    fitted_model, fit_info = fit_model(
        psf_sersic_image,
        psf_sersic_model,
        maxiter=10000,
        epsilon=1.4901161193847656e-10,
        acc=1e-9,
    )

    # Generate a model image from the fitted model
    fitted_model_image = model_to_image(fitted_model, imsize)

    # Check if fit is close to actual
    error_arr = abs(fitted_model_image - psf_sersic_image) / psf_sersic_image
    assert np.max(error_arr) < 0.01  # max error less than 1% error
Esempio n. 10
0
                      y_stddev=3.),
 astmodels.KingProjectedAnalytic1D(amplitude=10., r_core=5., r_tide=2.),
 astmodels.Logarithmic1D(amplitude=10., tau=3.5),
 astmodels.Lorentz1D(amplitude=10., x_0=0.5, fwhm=2.5),
 astmodels.Moffat1D(amplitude=10., x_0=0.5, gamma=1.2, alpha=2.5),
 astmodels.Moffat2D(amplitude=10., x_0=0.5, y_0=1.5, gamma=1.2, alpha=2.5),
 astmodels.Planar2D(slope_x=0.5, slope_y=1.2, intercept=2.5),
 astmodels.RedshiftScaleFactor(z=2.5),
 astmodels.RickerWavelet1D(amplitude=10., x_0=0.5, sigma=1.2),
 astmodels.RickerWavelet2D(amplitude=10., x_0=0.5, y_0=1.5, sigma=1.2),
 astmodels.Ring2D(amplitude=10., x_0=0.5, y_0=1.5, r_in=5., width=10.),
 astmodels.Sersic1D(amplitude=10., r_eff=1., n=4.),
 astmodels.Sersic2D(amplitude=10.,
                    r_eff=1.,
                    n=4.,
                    x_0=0.5,
                    y_0=1.5,
                    ellip=0.0,
                    theta=0.0),
 astmodels.Sine1D(amplitude=10., frequency=0.5, phase=1.),
 astmodels.Cosine1D(amplitude=10., frequency=0.5, phase=1.),
 astmodels.Tangent1D(amplitude=10., frequency=0.5, phase=1.),
 astmodels.ArcSine1D(amplitude=10., frequency=0.5, phase=1.),
 astmodels.ArcCosine1D(amplitude=10., frequency=0.5, phase=1.),
 astmodels.ArcTangent1D(amplitude=10., frequency=0.5, phase=1.),
 astmodels.Trapezoid1D(amplitude=10., x_0=0.5, width=5., slope=1.),
 astmodels.TrapezoidDisk2D(amplitude=10.,
                           x_0=0.5,
                           y_0=1.5,
                           R_0=5.,
                           slope=1.),
Esempio n. 11
0
def generate_petrosian_sersic_correction(output_yaml_name,
                                         psf=None,
                                         r_eff_list=None,
                                         n_list=None,
                                         oversample=('x_0', 'y_0', 10, 10),
                                         plot=True):
    """
    This function generates corrections for Petrosian radii by simulating a galaxy image and measuring its properties.
    This is done to identify the correct `epsilon` value that, multiplied with `r_petrosian`, would give `r_total_flux`.
    To achieve this, an image created from a Sersic model and convolved with a PSF (if provided). The Petrosian radii
    and concentrations are computed using the default `epsilon` = 2. Since the real `r_total_flux` of the simulated galaxy
    is known, the correct `epsilon` can be determined by `epsilon = r_petrosian / r_total_flux`. The resulting grid will
    be used to map measured `r_petrosian` and `C2080` to the correct `epsilon` value. After the gird is computed, it
    will be saved to a yaml file which is readable by `petrofit.petrosian.PetrosianCorrection`.

    Parameters
    ----------
    output_yaml_name : str
        Name of output file, must have .yaml or .yml extension.

    psf : numpy.array or None
        2D PSF image to pass to `petrofit.fitting.models.PSFConvolvedModel2D`.

    r_eff_list : list, (optional)
        List of `r_eff` (half light radii) in pixels to evaluate.

    n_list : list, (optional)
        List of Sersic indices to evaluate.

    oversample : int or tuple
        oversampling to pass to `petrofit.fitting.models.PSFConvolvedModel2D`.

    plot : bool
        Shows plot of photometry and Petrosian.

    Returns
    -------
    petrosian_grid : dict
        Dictionary that is readable by `petrofit.petrosian.PetrosianCorrection`
        Also saves Yaml file that is readable by `petrofit.petrosian.PetrosianCorrection`.
    """

    if r_eff_list is None:
        r_eff_list = np.arange(10, 100 + 5, 5)

    if n_list is None:
        n_list = np.arange(0.5, 6.0 + 0.5, 0.5)

    petrosian_grid = {}

    with ProgressBar(len(r_eff_list) * len(n_list),
                     ipython_widget=True) as bar:

        for r_eff_idx, r_eff in enumerate(r_eff_list):

            c_pet_list_output = []
            n_list_output = []
            r_p_list_output = []
            epsilon_list_output = []
            r_p_hl_list_output = []

            for n_idx, n in enumerate(n_list):
                bar.update()

                n = np.round(n, 2)
                amplitude = 100 / np.exp(gammaincinv(2. * n, 0.5))

                # Total flux
                total_flux = sersic_enclosed(np.inf,
                                             amplitude=amplitude,
                                             r_eff=r_eff,
                                             n=n)
                total_flux = total_flux * 0.99

                # Total flux radius
                r_total_flux = sersic_enclosed_inv(total_flux,
                                                   amplitude=amplitude,
                                                   r_eff=r_eff,
                                                   n=n)
                ori_r_total_flux = r_total_flux
                max_r = r_total_flux * 2 if n < 2 else r_total_flux * 1.2

                # Make r_list
                if max_r >= 200:
                    r_list = [x for x in range(1, 201, 2)]
                    r_list += [x for x in range(300, int(max_r) + 100, 100)]
                else:
                    r_list = [x for x in range(1, int(max_r) + 2, 2)]
                r_list = np.array(r_list)

                image_size = max(r_list) * 2

                x_0 = image_size // 2
                y_0 = image_size // 2

                # Define model
                galaxy_model = models.Sersic2D(
                    amplitude=amplitude,
                    r_eff=r_eff,
                    n=n,
                    x_0=x_0,
                    y_0=y_0,
                    ellip=0.,
                    theta=0.,
                )

                # PSF weap
                galaxy_model = PSFConvolvedModel2D(galaxy_model,
                                                   psf=psf,
                                                   oversample=oversample)

                galaxy_image = model_to_image(galaxy_model,
                                              image_size,
                                              center=(x_0, y_0))

                flux_list, area_list, err = photometry_step(
                    (image_size // 2, image_size // 2),
                    r_list,
                    galaxy_image,
                    plot=plot,
                    vmax=amplitude / 100)
                plt.show()

                if plot:
                    print(r_eff, n, r_total_flux)
                    plt.show()

                # Petrosian from Photometry
                p = Petrosian(r_list, area_list, flux_list)
                rc1, rc2, c_index = p.concentration_index()
                if np.any(np.isnan(np.array([rc1, rc2, c_index]))):
                    raise Exception("concentration_index cant be computed")

                # Compute new r_total_flux
                u, indices = np.unique(flux_list, return_index=True)
                indices = np.array(indices)
                f = interp1d(flux_list[indices],
                             r_list[indices],
                             kind='linear')
                corrected_r_total_flux = f(total_flux)

                # Compute corrections
                corrected_epsilon = corrected_r_total_flux / p.r_petrosian
                corrected_p = copy(p)
                corrected_p.epsilon = corrected_epsilon
                if plot:
                    corrected_p.plot(True, True)
                    plt.show()
                    print(corrected_epsilon)
                    print(r_eff, p.r_half_light, corrected_p.r_half_light)
                    print(ori_r_total_flux, p.r_total_flux,
                          corrected_p.r_total_flux, corrected_r_total_flux)
                    print(" ")

                c_pet_list_output.append(p.concentration_index()[-1])
                n_list_output.append(n)
                r_p_list_output.append(p.r_petrosian)
                epsilon_list_output.append(corrected_epsilon)
                r_p_hl_list_output.append(corrected_p.r_half_light)

                del galaxy_model, galaxy_image

            petrosian_grid[r_eff] = {
                'c_index': c_pet_list_output,
                'n': n_list_output,
                'epsilon': epsilon_list_output,
                'r_petrosian': r_p_list_output,
                'r_hl_petrosian': r_p_hl_list_output
            }

    if output_yaml_name is not None:
        with open(output_yaml_name, 'w') as outfile:
            print(outfile.name)
            yaml.dump(petrosian_grid, outfile)

    return petrosian_grid
Esempio n. 12
0
def remove_fitted_sources(image, image_residual, cat,
                          r_inner_mult=1,
                          r_outter_mult=7,
                          r_output_mult=20,
                          index_start=None, index_end=None,
                          n_models=2,
                          show_progress=True,
                          print_fit=False,
                          show_fit=True):
    """
    Fits and removes bright sersic profiles from image.

    Parameters
    ----------
    image : array
        Input image to remove sources from. This image should be noise subtracted
    image_residual : array
        Image resulting from subtracting the input image by all the catalog sources.
    cat : `SourceCatalog` instance
        A `SourceCatalog` instance containing the properties of each
        source.
    r_inner_mult : int
        Multiples the object radius to give the radius of the object's core. Should be >= 1.
    r_outter_mult : int
        Multiples the object radius to give the radius of the outer components. Should be >= 1.
    r_output_mult : int
        Multiples the object radius to give the radius of the final cutout that is subtracted from the image.
        Should be >= 1.
    index_start : int
        Index of the first source in the area sorted catalog. So if this is set to 0,
        it will start removing at the object with the largest area in the catalog.
    index_end : int
        Index of last source in the area sorted catalog.
    n_models : int
        Number of models to use for fitting
        1 = Sersic2D
        2 = Sersic2D_core + Sersic2D_outter
        3 = Sersic2D_core + Sersic2D_outter + models.Gaussian2D
        all models are centered around the same pixel (the core).
    show_progress : bool
        Show jupyter notebook progress bar
    print_fit : bool
        Print fit params
    show_fit : bool
        Plot fit

    Returns
    -------
    subtracted_image : array
        An image with the fitted sources subtracted from it.

    subtracted_image_residual : array
        The input residual image with the fitted sources subtracted from it.

    fitted_sources : array
        An image showing only the fitted sources from the models.
    """

    order = order_cat(cat)

    order = order[index_start:index_end]

    if show_progress:
        pb = widgets.IntProgress(
            value=0,
            min=0,
            max=len(order),
            step=1,
            description='Loading:',
            bar_style='',
            orientation='horizontal'
        )

        display(pb)

    # Copy image for output
    image_copy = image.copy()
    image_residual_copy = image_residual.copy()
    image_zero = np.zeros_like(image_copy)
    photometric_sums = {}

    for i, cat_index in enumerate(order):
        if show_fit or print_fit:
            print(index_start + i, cat_index)

        if show_progress:
            # Update progress bar
            pb.value = i + 1
            pb.description = "{}/{}".format(pb.value, len(order))

        # Load object and aperture
        obj = cat[cat_index]

        # Estimate center of bobject
        cut = obj.segment.make_cutout(image, masked_array=True)
        cy, cx = np.unravel_index(cut.argmax(), cut.shape)

        x = obj.segment.bbox.ixmin + cx
        y = obj.segment.bbox.iymin + cy

        # Estimate other parts
        theta = obj.orientation.to(u.rad).value
        ellip = (1 - obj.semiminor_axis_sigma.value / obj.semimajor_axis_sigma.value)
        amp = cut.data.max()

        # Define fitting radius
        r_object = int(np.round(obj.semimajor_axis_sigma.value))  # inner cutout radius

        r_inner = r_object * r_inner_mult

        r_outter = r_object * r_outter_mult

        # Make images to fit
        target_zoom = cutout(image_copy, x, y, r_inner)
        target = cutout(image_copy, x, y, r_outter)
        target_residual = cutout(image_residual_copy, x, y, r_outter)

        # Fit inner core
        # --------------

        # Find center of zoomed cutout image
        y_0, x_0 = np.array(target_zoom.shape) // 2

        # Make inner model
        xy_slack = 10  # x and y value range / 2

        model_1 = models.Sersic2D(
            amplitude=amp,
            n=2,
            r_eff=r_inner,
            ellip=ellip,
            theta=theta,
            x_0=x_0,
            y_0=y_0,
            # fixed={'theta':True, 'ellip':True},
            bounds={
                'amplitude': (0, None),
                'r_eff': (0, None),
                'n': (0, 6),
                'ellip': (0, 1),
                'theta': (0, 2 * np.pi),
                'x_0': (x_0 - xy_slack, x_0 + xy_slack),
                'y_0': (y_0 - xy_slack, y_0 + xy_slack),
            })

        # Fit core model to zoomed cutout to tighten first guess
        model_1, fit = fit_model(target_zoom, model_1, maxiter=10000, epsilon=1e-40)

        # Fix the center x and y of all models to match the fitted guess
        """
        for pn in model.param_names:
            model.fixed[pn] = True            
        """

        model_1.fixed.update({
            'x_0': True,
            'y_0': True,
        })

        del model_1.bounds['x_0']
        del model_1.bounds['y_0']

        # Fit glow around target
        # ----------------------

        # Remove old center and add new center
        y_0, x_0 = np.array(target_zoom.shape) // 2

        model_1.x_0 -= x_0
        model_1.y_0 -= y_0

        y_0, x_0 = np.array(target.shape) // 2

        model_1.x_0 += x_0
        model_1.y_0 += y_0

        # Setup second model for fitting
        xy_slack = 5

        model_2 = models.Sersic2D(
            amplitude=0,
            n=0.1,
            r_eff=model_1.r_eff * 3,
            ellip=ellip,
            theta=theta,
            x_0=model_1.x_0,
            y_0=model_1.y_0,
            fixed={'x_0': True, 'y_0': True, 'theta': True, 'ellip': True},
            bounds={
                'amplitude': (0, None),
                'r_eff': (0, None),
                'n': (0, 2),
                'ellip': (0, 1),
                'theta': (0, 2 * np.pi),
            })

        # Fit second model to the residual of the image (image with segmented area masked)
        model_2, fits = fit_model(target_residual, model_2, maxiter=10000, epsilon=1e-40)

        # PSF Models
        # ----------

        # Setup PSF image and fit it to image of target to estimate param guess

        # Normal sources
        model_3 = models.Gaussian2D(
            amplitude=amp,
            x_mean=model_1.x_0,
            y_mean=model_1.y_0,
            x_stddev=model_1.r_eff,
            y_stddev=model_1.r_eff,
            fixed={'x_mean': True, 'y_mean': True, }
        )

        model_3, fits = fit_model(target, model_3, maxiter=10000, epsilon=1e-40)

        # Final Fit
        # ---------

        # Combine models
        if n_models == 1:
            model = model_1
        elif n_models == 2:
            model = model_1 + model_2
        elif n_models == 3:
            model = model_1 + model_2 + model_3
        else:
            raise Exception("n_models should be 1, 2 or 3")

        # Fit combined model
        model, fit = fit_model(target, model, maxiter=10000, epsilon=1e-40)
        model, fit = fit_model(target, model, maxiter=10000, epsilon=1e-40)

        # Make center of model the center of model_1
        model.x_0 = model_1.x_0
        model.y_0 = model_1.y_0

        # Plot and Print
        # --------------
        if show_fit:
            fig, ax = plot_fit(target, model)  # , vmin=vmin, vmax=vmax)
            plt.show()

        if print_fit:
            print("\n".join([str(j) for j in zip(model.param_names, model.parameters)]) + "\n" * 3)

        # Subtract from image
        # -------------------

        if fit.fit_info['ierr'] > 4:
            # Fit failed
            continue

        # Make new image
        size = r_inner * r_output_mult
        y_arange, x_arange = np.mgrid[
                             int(model.y_0.value) - size:int(model.y_0.value) + size,
                             int(model.x_0.value) - size:int(model.x_0.value) + size, ]
        model_image = model(x_arange, y_arange)

        # Subtract cutout from main copy image
        image_copy = model_subtract(image_copy, np.array(model_image), x, y)
        image_copy = np.clip(image_copy, 0, image_copy.max())
        #image_copy[y - 8:y + 8, x - 8:x + 8] = np.nan

        # Add cutout to main cutout only image
        image_zero = model_subtract(image_zero, -1 * np.array(model_image), x, y)

        # Subtract cutout second component from residual image
        image_residual_copy = model_subtract(image_residual_copy, np.array(model_image), x, y)
        image_residual_copy = np.clip(image_residual_copy, 0, image_residual_copy.max())

        # Photometry
        photometric_sums[obj.label] = model_image.sum()

    return image_copy, image_residual_copy, image_zero, photometric_sums
Esempio n. 13
0
import scipy.ndimage as ndi
from astropy.visualization import simple_norm
from astropy.modeling import models
from astropy.convolution import convolve
import photutils
import time
import statmorph
# %matplotlib inline

#%%
ny, nx = 240, 240
y, x = np.mgrid[0:ny, 0:nx]
sersic_model = models.Sersic2D(amplitude=1,
                               r_eff=20,
                               n=2.5,
                               x_0=120.5,
                               y_0=96.5,
                               ellip=0.5,
                               theta=-0.5)
image = sersic_model(x, y)
plt.imshow(image,
           cmap='gray',
           origin='lower',
           norm=simple_norm(image, stretch='log', log_a=10000))
plt.show()

#%%
size = 20  # on each side from the center
sigma_psf = 2.0
y, x = np.mgrid[-size:size + 1, -size:size + 1]
psf = np.exp(-(x**2 + y**2) / (2.0 * sigma_psf**2))
Esempio n. 14
0
def fitSersic(image: np.ndarray,
              centroid: List[float],
              fwhms: List[float],
              theta: float,
              starMask=None):
    '''Function that fits a 2D sersic function to an image of a Galaxy.

    Parameters
    ----------

    image : np.ndarray
        image to which a 2D Sersic function will be fit
    centroid : List[float]
        Centre of object of interest
    fwhms : List[float]
        Full width half maximums of object
    theta : float
        rotation of object anticlockwise from positive x axis
    starMask : np.ndarray
        Mask contains star locations.

    Returns
    -------

    Parameters : astropy.modeling.Model object

        Collection of best fit parameters for the 2D sersic function

    '''

    if starMask is None:
        imageCopy = image
    else:
        imageCopy = image * starMask

    fit_p = fitting.LevMarLSQFitter()

    # amplitude => Surface brightness at r_eff
    # r_eff => Effective (half-light) radius
    # n => sersic index, guess 1.?

    b = 2. * min(fwhms)
    a = 2. * max(fwhms)
    ellip = 1. - (b / a)

    apertureTotal = EllipticalAperture(centroid, a, b, theta)
    totalSum = apertureTotal.do_photometry(imageCopy, method="exact")[0][0]

    # get bracketing values for root finder to find r_eff
    deltaA = (a / 100.) * 2.
    aCurrent = a - deltaA
    aMin = 0
    aMax = 0
    while True:
        apertureCurrent = EllipticalAperture(centroid, aCurrent, b, theta)
        currentSum = apertureCurrent.do_photometry(imageCopy,
                                                   method="exact")[0][0]
        currentFraction = currentSum / totalSum
        if currentFraction <= .5:
            aMin = aCurrent
            aMax = aCurrent + deltaA
            break
        aCurrent -= deltaA

    # get root
    r_eff = brentq(_fractionTotalFLuxEllipse,
                   aMin,
                   aMax,
                   args=(imageCopy, b, theta, centroid, totalSum))

    # calculate amplitude at r_eff
    a_in = r_eff - 0.5
    a_out = r_eff + 0.5
    b_out = a_out - (1. * ellip)
    ellip_annulus = EllipticalAnnulus(centroid, a_in, a_out, b_out, theta)
    totalR_effFlux = ellip_annulus.do_photometry(imageCopy,
                                                 method="exact")[0][0]
    meanR_effFlux = totalR_effFlux / ellip_annulus.area

    sersic_init = models.Sersic2D(amplitude=meanR_effFlux,
                                  r_eff=r_eff,
                                  n=2.0,
                                  x_0=centroid[0],
                                  y_0=centroid[1],
                                  ellip=ellip,
                                  theta=theta)

    ny, nx = imageCopy.shape
    y, x = np.mgrid[0:ny, 0:nx]

    Parameters = fit_p(sersic_init, x, y, imageCopy, maxiter=1000, acc=1e-8)

    return Parameters
Esempio n. 15
0
def make_image():
    """Make 2D Sersic2D image"""
    imsize = 500

    d = 5

    sersic_model = models.Sersic2D(
        amplitude=1,
        r_eff=25,
        n=2,
        x_0=imsize / 2,
        y_0=imsize / 2,
        ellip=0,
        theta=0,
        bounds={
            'amplitude': (0., None),
            'r_eff': (0, None),
            'n': (0, 10),
            'ellip': (0, 1),
            'theta': (-2 * np.pi, 2 * np.pi),
        },
    )

    sersic_model += models.Sersic2D(
        amplitude=1,
        r_eff=25,
        n=2,
        x_0=imsize * 0.75,
        y_0=imsize * 0.75,
        ellip=0.5,
        theta=np.pi / 4,
        bounds={
            'amplitude': (0., None),
            'r_eff': (0, None),
            'n': (0, 10),
            'ellip': (0, 1),
            'theta': (-2 * np.pi, 2 * np.pi),
        },
    )

    sersic_model += models.Sersic2D(
        amplitude=1,
        r_eff=25,
        n=1,
        x_0=imsize * 0.25,
        y_0=imsize * 0.25,
        ellip=0.2,
        theta=np.pi / 6,
        bounds={
            'amplitude': (0., None),
            'r_eff': (0, None),
            'n': (0, 10),
            'ellip': (0, 1),
            'theta': (-2 * np.pi, 2 * np.pi),
        },
    )

    model_image = model_to_image(sersic_model, imsize)

    image_mean, image_median, image_stddev = sigma_clipped_stats(model_image,
                                                                 sigma=3)

    # model_image += np.random.normal(0, 3*image_stddev, size=model_image.shape)

    wcs = WCS()

    header = wcs.to_header()

    for param_name, param_val in zip(sersic_model.param_names,
                                     sersic_model.parameters):
        header[param_name] = param_val

    header['BUNIT'] = 'electron / s '

    path = "sersic_2d_image.fits.gz"
    sersic_2d_path = os.path.join(os.path.dirname(__file__), path)
    fits.writeto(sersic_2d_path,
                 data=model_image,
                 header=header,
                 overwrite=True)
def make_niriss_image(plot=False):
    """
    Create a direct image with sources that have been convolved with the 
    NIRISS PSF from webbpsf as well as the segmentation (ID) image.
    
    Args:
        plot (Bool): True if plots should be saved.
    """

    # Add only ra-dec, rotation, and wcs to add the sources at the right places
    # `size` is image dimension in arcsec
    hdu = grizli.utils.make_wcsheader(size=NAXIS[0] * 0.0656,
                                      pixscale=0.0656,
                                      get_hdu=True)
    nis_header = hdu.header
    nis_header["CRVAL1"] = RA_CENTER
    nis_header["CRVAL2"] = DEC_CENTER

    # Rotate image to desired PA
    nis_wcs = pywcs.WCS(nis_header)
    cd_rot = rotate_CD_matrix(nis_wcs.wcs.cd, PA_APER)
    for i in range(2):
        for j in range(2):
            nis_header["CD{0}_{1}".format(i + 1, j + 1)] = cd_rot[i][j]
    nis_wcs = pywcs.WCS(nis_header)
    nis_wcs.pscale = 0.0656  #grizli.utils.get_wcs_pscale(nis_wcs)
    nis_header["PA_APER"] = PA_APER

    # Load the catalog and compute detector flux
    gfit = Table.read(SOURCE_CATALOG, format='ascii.commented_header')
    object_mag = gfit[MAG_COL]
    ZP = ZPs[NIS_FILTER.lower()]
    object_flux = 10**(-0.4 * (object_mag - ZP))

    # Determine which objects are within the NIRISS FoV
    xc, yc = nis_wcs.all_world2pix(gfit['ra'], gfit['dec'], 0)
    obj_in_img = (xc > 1) & (yc > 1) & (xc < NAXIS[0] - 1) & (yc <
                                                              NAXIS[1] - 1)
    obj_in_img &= object_flux > 0

    # Point sources and faint sources
    stars = obj_in_img & ((gfit['star_flag'] == 1) | (object_mag > MAX_MAG))
    star_idx = np.arange(len(gfit))[stars]

    # Galaxies
    if 're' not in gfit.colnames:
        gals = obj_in_img < -100  # False
    else:
        gals = obj_in_img & (~stars) & (object_mag <= MAX_MAG) & (gfit['re'] >
                                                                  0)
    gal_idx = np.arange(len(gfit))[gals]

    # Put sources in the image
    # Initialize model and segmentation images with zeros
    nis_model = np.zeros(NAXIS[::-1], dtype=np.float32)
    nis_seg = np.zeros(NAXIS[::-1], dtype=int)

    # pixel indices
    yp, xp = np.indices(NAXIS[::-1])

    # Add star point sources
    xpix = np.cast[int](np.round(xc))
    ypix = np.cast[int](np.round(yc))
    for ix in star_idx:
        nis_model[ypix[ix], xpix[ix]] = object_flux[ix]

    if SEG_THRESHOLD > 0:
        Rseg = 5
        for i, ix in enumerate(star_idx):
            print('seg: {0} ({1}/{2})'.format(ix, i, stars.sum()))
            R = np.sqrt((xp - xpix[ix])**2 + (yp - ypix[ix])**2)
            clip_seg = (R <= Rseg) & (nis_seg == 0)
            nis_seg[clip_seg] = gfit['id'][ix]

    # Add Sersic sources
    for i, ix in enumerate(gal_idx):
        print('ID: {0} ({1}/{2})'.format(ix, i, gals.sum()))

        # Effective radius, in pixels
        re = gfit['re'][ix] / nis_wcs.pscale
        se = models.Sersic2D(amplitude=1.,
                             r_eff=re,
                             n=gfit['n'][ix],
                             x_0=xc[ix],
                             y_0=yc[ix],
                             ellip=1 - gfit['q'][ix],
                             theta=(gfit['pa'][ix] + 90 - PA_APER) / 180 *
                             np.pi)

        # Normalize to catalog flux
        m = se(xp, yp)
        renorm = object_flux[ix] / m.sum()
        if not np.isfinite(renorm):
            continue

        # Add to model image
        nis_model += m * renorm
        if SEG_THRESHOLD > 0:
            # Add to segmentation image
            clip_seg = (m * renorm > SEG_THRESHOLD) & (nis_seg == 0)
            nis_seg[clip_seg] = gfit['id'][ix]

    # Check image
    if plot is True:
        plt.figure(figsize=(10, 10))
        plt.subplot(projection=pywcs.WCS(nis_header))
        plt.imshow(np.log10(nis_model))
        #plt.imshow(nis_seg)
        plt.grid(color='black', ls='solid')
        plt.xlabel('Galactic Longitude')
        plt.ylabel('Galactic Latitude')
        plt.title("Sources (logscale)")
        figname = "{}_sources.png".format(OUTROOT)
        plt.savefig(figname)
        print("Wrote {}".format(figname))
        #plt.show()

    # Convolve with NIRISS PSF and save image and segmentation map.
    nis = webbpsf.NIRISS()
    # Add -0.5, -0.5 pixel offset to get convolved image in correct place ??
    nis.options[
        'source_offset_r'] = 0.5 * nis_wcs.pscale  # offset in arcseconds
    nis.options['source_offset_theta'] = 135.  # degrees CCW from +Y

    # Get the PSF
    nis.filter = NIS_FILTER.upper()
    psf_hdu = nis.calcPSF(fov_pixels=64)  # power of 2 for fast FFT convolution
    psf = psf_hdu[1].data
    psf /= psf.sum()

    # Convolve the model image
    nis_fullsim = stsci.convolve.convolve2d(nis_model,
                                            psf,
                                            output=None,
                                            mode='nearest',
                                            cval=0.0,
                                            fft=1)

    # Mask low fluxes to make images gzip smaller
    #mask = nis_fullsim > CLIP_FLUX
    #nis_fullsim[~mask] = 0

    # Save the output image
    filename = '{0}-{1}.fits'.format(OUTROOT, nis.filter.lower())
    fits.writeto(filename,
                 data=nis_fullsim,
                 header=nis_header,
                 overwrite=True,
                 output_verify='fix')
    print("Wrote {}".format(filename))

    # Save the segmentation image
    if SEG_THRESHOLD > 0:
        filename = '{0}-{1}_seg.fits'.format(OUTROOT, nis.filter.lower())
        fits.writeto(filename,
                     data=nis_seg,
                     header=nis_header,
                     overwrite=True,
                     output_verify='fix')
        print("Wrote {}".format(filename))

    # Check image.
    if plot is True:
        plt.subplot(projection=pywcs.WCS(nis_header))
        #        plt.imshow(nis_fullsim)
        plt.imshow(np.log10(nis_fullsim))
        #plt.imshow(nis_seg)
        plt.grid(color='black', ls='solid')
        plt.xlabel('Galactic Longitude')
        plt.ylabel('Galactic Latitude')
        plt.title("Distorted sources convolved with PSF (logscale)")
        figname = "{}_sourcepsf.png".format(OUTROOT)
        plt.savefig(figname)
        print("Wrote {}".format(figname))