コード例 #1
0
def get_hpd_from_image_fit(image, pix_size=0.020, arcsec=arcsec):
    cdisp_dir_counts = sum(image, axis=0)
    fit_levmar = fitting.SimplexLSQFitter()
    gmodel = models.Gaussian1D()
    g = fit_levmar(gmodel,
                   range(len(cdisp_dir_counts)),
                   cdisp_dir_counts,
                   acc=1e-6)
    return g.stddev * 2.35 * pix_size / arcsec, cdisp_dir_counts, g(
        range(len(cdisp_dir_counts)))
コード例 #2
0
def get_fwhm_from_image_fit(image, pix_size=0.020, arcsec=arcsec):
    disp_dir_counts = sum(image, axis=1)
    fit_levmar = fitting.SimplexLSQFitter()
    lmodel = models.Lorentz1D()
    lmodel.amplitude, lmodel.x0, lmodel.fwhm = max(disp_dir_counts), float(
        len(disp_dir_counts)) / 2, 2.35
    l = fit_levmar(lmodel,
                   range(len(disp_dir_counts)),
                   disp_dir_counts,
                   acc=1e-6)
    return l.fwhm * pix_size / arcsec, disp_dir_counts, l(
        range(len(disp_dir_counts)))
コード例 #3
0
ファイル: qso.py プロジェクト: caridlin/CWITools
    def model_data(self):

        #Astropy Simplex LSQ Fitter for PSFs
        fitter = fitting.SimplexLSQFitter()

        #Try to fit Moffat in X direction
        try:
            moffatx_init = models.Moffat1D(1.2 * np.max(self.xdata), self.x,
                                           1.0, 1.0)
            moffatx_fit = fitter(moffatx_init, self.X[self.x0:self.x1],
                                 self.xdata[self.x0:self.x1])
            self.xmoff = moffatx_fit(self.Xs)
            self.x_opt = moffatx_fit.x_0.value
        except:
            self.xmoff = np.zeros_like(self.Xs)
            self.x_opt = self.x

        #Try to fit Moffat in Y direction
        try:
            #self.ydata -= np.median(self.ydata)
            moffaty_init = models.Moffat1D(1.2 * np.max(self.ydata), self.y,
                                           1.0, 1.0)
            moffaty_fit = fitter(moffaty_init, self.Y[self.y0:self.y1],
                                 self.ydata[self.y0:self.y1])
            self.ymoff = moffaty_fit(self.Ys)
            self.y_opt = moffaty_fit.x_0.value
        except:
            self.ymoff = np.zeros_like(self.Ys)
            self.y_opt = self.y

        #Update upper and lower bounds for fitting PSF
        self.x0 = max(0, self.x - self.dx)
        self.x1 = min(self.X[-1] - 1, self.x + self.dx)

        self.y0 = max(0, self.y - self.dy)
        self.y1 = min(self.Y[-1] - 1, self.y + self.dy)
コード例 #4
0
ファイル: 1.py プロジェクト: Jayshil/Galaxies
xx = np.linspace(np.min(asc), np.max(asc), 1000)


#-----------------------------------------------------------------
#
#--------------------Fitting using Astropy------------------------
#
#-----------------------------------------------------------------

print('-----------------------------------------')
print('                                         ')
print('            Astropy Fitting              ')
print('                                         ')
print('-----------------------------------------')
s1 = src()
fit_s1 = fitting.SimplexLSQFitter()
s1_fit = fit_s1(s1, x=asc, y=sb, maxiter=10000, weights=1/sbe)
print('                                         ')
print(s1_fit)
print('                                         ')

residuals = sb - s1_fit(asc)
#----------For figure
fig1 = plt.figure(figsize = (8,10))
gs1 = gd.GridSpec(2, 1, height_ratios = [4,1])

ax1 = plt.subplot(gs1[0])

ax1.errorbar(asc, sb, yerr=sbe, color='orangered', fmt='.', alpha=0.5, label='Data')
ax1.plot(xx, s1_fit(xx), color='orangered', label='Best fit Sersic profile')
ax1.grid()
コード例 #5
0
class AstropyQSpectraFit(ProcessingPlugin):
    name = 'Q Fit (Astropy)'

    q = InOut(description='Q bin center positions',
              type=np.array)
    Iq = InOut(description='Q spectra bin intensities', type=np.array)
    model = Input(description='Fittable model class in the style of Astropy', type=Enum)
    domainmin = Input(description='Min bound on the domain of the input data', type=float)
    domainmax = Input(description='Max bound on the domain of the input data', type=float)
    fitter = Input(description='Fitting algorithm', default=fitting.LevMarLSQFitter(), type=Enum,
                   limits={'Linear LSQ': fitting.LinearLSQFitter(),
                           'Levenberg-Marquardt LSQ': fitting.LevMarLSQFitter(), 'SLSQP LSQ': fitting.SLSQPLSQFitter(),
                           'Simplex LSQ': fitting.SimplexLSQFitter()})

    fittedmodel = Output(description='A new model with the fitted parameters; behaves as parameterized function',
                         type=Fittable1DModel)
    fittedprofile = Output(
        description='The fitted profile from the evaluation of the resulting model over the input range.')

    hints = [PlotHint(q, Iq), PlotHint(q, fittedprofile)]

    modelvars = {}

    def __init__(self):
        super(AstropyQSpectraFit, self).__init__()
        self.model.limits = {plugin.name: plugin.plugin_object for plugin in
                             pluginmanager.getPluginsOfCategory('Fittable1DModelPlugin')}
        self.model.value = list(self.model.limits.values())[0]

    @property
    def parameter(self):

        # clear cache in
        for input in self.modelvars:
            del self.__dict__[input]
        varcache = self.modelvars.copy()
        self.modelvars = {}
        self._inputs = None
        self._inverted_vars = None
        if hasattr(self, '_inverted_vars'): del self._inverted_vars

        for name in self.model.value.param_names:
            param = getattr(self.model.value, name)
            # TODO: CHECK NAMESPACE
            if name in varcache:
                input = varcache[name]
            else:
                input = InOut(name=name, default=param.default, limits=param.bounds, type=float, fixed=False,
                              fixable=True)
            setattr(self, name, input)
            self.modelvars[name] = input
        parameter = super(AstropyQSpectraFit, self).parameter
        parameter.child('model').sigValueChanged.connect(self.reset_parameter)
        return parameter

    def reset_parameter(self):
        # cache old parameter
        oldparam = self._param

        # empty it
        for child in oldparam.children():
            child.remove()

        # reset attribute so new parameter is generated
        self._param = None

        # add new children to old parameter
        for child in self.parameter.children():  # type: Parameter
            oldparam.addChild(child)

        # set old parameter to attribute
        self._param = oldparam

    def evaluate(self):
        if self.model.value is None or self.model.value == '----': return
        norange = self.domainmin.value == self.domainmax.value
        if self.domainmin.value is None and self.q.value is not None or norange:  # truncate the q and I arrays with limits
            self.domainmin.value = self.q.value.min()
        if self.domainmax.value is None and self.q.value is not None or norange:  # truncate the q and I arrays with limits
            self.domainmax.value = self.q.value.max()
        for name, input in self.modelvars.items():  # propogate user-defined values to the model
            getattr(self.model.value, name).value = input.value
            getattr(self.model.value, name).fixed = input.fixed
        filter = np.logical_and(self.domainmin.value <= self.q.value, self.q.value <= self.domainmax.value)
        q = self.q.value[filter]
        Iq = self.Iq.value[filter]
        self.fittedmodel.value = self.fitter.value(self.model.value, q, Iq)
        self.fittedprofile.value = self.fittedmodel.value(self.q.value)

    def getCategory() -> str:
        return "Fits"
コード例 #6
0
    def goodimage(self,
                  data,
                  camera,
                  psfx=1.3,
                  fitmax=.2,
                  xrange=[1024, 2048],
                  yrange=[512, 1536],
                  maxp=50000.,
                  nplot=100,
                  background=None,
                  noise=None,
                  sources=None,
                  model='simp',
                  det_sigma=5.0,
                  base_fwhm=8.0,
                  plot_stuff=False,
                  expid=None):
        '''
		test if an image has a star with a good psf in its center
		'''
        log = logging.getLogger('star_sizes')
        from astropy.modeling import models, fitting
        if background == None or noise == None:
            log.debug("Finding background level...")
            mean, median, std = sigma_clipped_stats(data, sigma=5.0, iters=2)
            background = median
            noise = std
            print(background, noise)
        global cic_count
        global cis_count
        global cin_count
        global ciw_count
        global cie_count
        # Detect sources
        #print('base fwhm'+str(base_fwhm))
        if sources == None:
            log.debug("Detecting sources..")
            daofind = DAOStarFinder(fwhm=base_fwhm,
                                    threshold=det_sigma * noise)
            sources = daofind(data - background)
            #print('found '+str(len(sources))+' sources')
        # Sort by SN
        w = sources['peak'] < maxp
        sources = sources[w]
        sources.sort('flux')
        sources.reverse()

        fwhm_array = []
        fwhm_weight_array = []
        x_coordinate = []
        y_coordinate = []
        final_func_val = []
        if len(sources) > nplot:
            sources = sources[:nplot]
        #print(len(sources))
        model_init = models.Gaussian1D(amplitude=1.0, mean=0, stddev=base_fwhm)

        for isource in sources:

            flux_counts = []
            pixel_distance = []
            npix = 0

            x_cen = int(isource['xcentroid'])
            y_cen = int(isource['ycentroid'])
            ##print(x_cen,y_cen)
            if x_cen >= xrange[0] and x_cen < xrange[1] and y_cen >= yrange[
                    0] and y_cen < yrange[1]:
                analysis_radius = 20
                #print(isource['peak'])
                try:
                    for x in range(x_cen - analysis_radius,
                                   x_cen + analysis_radius):
                        for y in range(y_cen - analysis_radius,
                                       y_cen + analysis_radius):
                            #flux_counts.append((data[y][x] - 0.) / isource['peak'])
                            val = (data[y][x] - background) / isource['peak']

                            flux_counts.append(val)
                            dis = numpy.linalg.norm((isource['xcentroid'] - x,
                                                     isource['ycentroid'] - y))
                            pixel_distance.append(dis)

                    flux_counts = np.array(flux_counts)
                    pixel_distance = np.array(pixel_distance)

                    w = (flux_counts > 0.5)  #& (flux_counts < 0.65)
                    psel = pixel_distance[w]
                    fsel = flux_counts[w]
                    mpsel = np.mean(psel)
                    wn = psel < 2. * mpsel
                    psel = psel[wn]
                    fsel = fsel[wn]
                    A = np.vstack([fsel, np.ones(len(psel))]).T
                    m, c = np.linalg.lstsq(A, psel, rcond=None)[0]
                    ssq = sum((psel - m * fsel + c)**2.) / float(len(psel))
                    fitter = fitting.SimplexLSQFitter()
                    fitted_model = fitter(model_init, psel, fsel)

                    iFWHM = 2.355 * fitted_model.stddev * self.pix_scale * self.micron_to_seeing[
                        camera]
                    #print(np.mean(psel),m*.5+c,ssq,iFWHM,fitter.fit_info['final_func_val'])
                    if iFWHM < psfx and fitter.fit_info[
                            'final_func_val'] < fitmax:
                        return True
                except:
                    pass
                    #print('hit edge?')

        return False
コード例 #7
0
    def estimate_fwhm(self,
                      data,
                      camera,
                      nstar=10,
                      background=None,
                      noise=None,
                      sources=None,
                      model='simp',
                      maxfitv=1.,
                      det_sigma=5.0,
                      base_fwhm=8.0,
                      plot_stuff=False,
                      expid=None):
        '''estimate fwhm for a single image
		plot_stuff:plot the fit for each single source
		return:fwhm of this image'''
        log = logging.getLogger('star_sizes')

        if background == None or noise == None:
            log.debug("Finding background level...")
            mean, median, std = sigma_clipped_stats(data, sigma=5.0, iters=2)
            background = median
            noise = std
            print(background, noise)
        global cic_count
        global cis_count
        global cin_count
        global ciw_count
        global cie_count
        # Detect sources
        #print('base fwhm'+str(base_fwhm))
        if sources == None:
            log.debug("Detecting sources..")
            daofind = DAOStarFinder(fwhm=base_fwhm,
                                    threshold=det_sigma * noise)
            sources = daofind(data - background)
            print('found ' + str(len(sources)) + ' sources')
        # Sort by SN
        sources.sort('flux')
        sources.reverse()

        fwhm_array = []
        fwhm_weight_array = []
        x_coordinate = []
        y_coordinate = []
        final_func_val = []
        if len(sources) > nstar:
            sources = sources[:nstar]
        model_init = models.Gaussian1D(amplitude=1.0, mean=0, stddev=base_fwhm)
        for isource in sources:
            flux_counts = []
            pixel_distance = []
            npix = 0

            x_cen = int(isource['xcentroid'])
            y_cen = int(isource['ycentroid'])
            ##print(x_cen,y_cen)
            analysis_radius = 20
            #print(isource['peak'])
            try:
                for x in range(x_cen - analysis_radius,
                               x_cen + analysis_radius):
                    for y in range(y_cen - analysis_radius,
                                   y_cen + analysis_radius):
                        #flux_counts.append((data[y][x] - 0.) / isource['peak'])
                        val = (data[y][x] - background) / isource['peak']

                        flux_counts.append(val)
                        dis = numpy.linalg.norm((isource['xcentroid'] - x,
                                                 isource['ycentroid'] - y))
                        pixel_distance.append(dis)

                flux_counts = np.array(flux_counts)
                pixel_distance = np.array(pixel_distance)

                w = (flux_counts > 0.5)  #& (flux_counts < 0.65)
                psel = pixel_distance[w]
                fsel = flux_counts[w]
                mpsel = np.mean(psel)
                wn = psel < 3. * mpsel
                psel = psel[wn]
                fsel = fsel[wn]
                #A = np.vstack([fsel, np.ones(len(psel))]).T
                #m, c = np.linalg.lstsq(A, psel, rcond=None)[0]
                #ssq = sum((psel-m*fsel+c)**2.)/float(len(psel))
                fitter = fitting.SimplexLSQFitter()
                fitted_model = fitter(model_init, psel, fsel)
                fitv = fitter.fit_info['final_func_val']
                iFWHM = 2.355 * fitted_model.stddev * self.pix_scale * self.micron_to_seeing[
                    camera]
                #if iFWHM/(m*.5+c) > 1:
                #	fitv = 999
                #print(np.mean(psel),m*.5+c,ssq,iFWHM,fitv)

                #fo.write(str(x_cen)+' '+str(y_cen)+' '+str(iFWHM)+ ' '+str(fitter.fit_info['final_func_val'])+' '+str(isource['peak'])+'\n')
                #plt.plot(pixel_distance,flux_counts,'k-')
                #plt.plot(psel,fsel,'ro')
                #plt.show()
                #if val > 0.5:
                #	print(dis)
                log.debug("\n>>>>> New source")

                log.debug(("Fit value:", fitter.fit_info['final_func_val']))
                log.debug(("SN:", isource['flux'] * det_sigma))
                log.debug(("single FWHM estimated: ", iFWHM))

                #if fitv < maxfitv:
                #print('final value less than 100, info going into arrays')
                x_coordinate.append(x_cen)
                y_coordinate.append(y_cen)
                fwhm_array.append(iFWHM)
                final_func_val.append(fitv)
                #print(iFWHM,fitter.fit_info['final_func_val'])
                fwhm_weight_array.append(isource['flux'] * det_sigma /
                                         fitter.fit_info['final_func_val'])
                #else:
                #print('final value greater than 100, no info for you')
                ##print(fitter.fit_info['final_func_val'])
                #if fitter.fit_info['final_func_val'] < 5.0:
                #   fwhm_array.append(iFWHM)
                #   fwhm_weight_array.append(isource['flux'] * det_sigma / fitter.fit_info['final_func_val'])
                #	print(fitv)
                #	color = 'red'
            except:
                #print('exception')
                pass

        if np.min(final_func_val) > maxfitv:
            maxfitv = 1.01 * np.min(
                final_func_val)  #ensure at least one point gets fit
        if len(fwhm_array) > 0:
            print(str(len(fwhm_array)) + ' stars found with some fwhm')
            #thredshold = np.array(fwhm_weight_array).max()*0.1
            fwhm_array_new = np.array(fwhm_array)[
                np.array(final_func_val) < maxfitv]
            print(str(len(fwhm_array_new)) + ' stars found with accepted fwhm')
            fwhm_weight_array_new = np.array(fwhm_weight_array)[
                np.array(final_func_val) < maxfitv]
            x_coordinate_new = np.array(x_coordinate)[
                np.array(final_func_val) < maxfitv]
            y_coordinate_new = np.array(y_coordinate)[
                np.array(final_func_val) < maxfitv]

            final_func_val_new = np.array(final_func_val)[
                np.array(final_func_val) < maxfitv]
            #FWHM_estimation = numpy.average(fwhm_array_new, weights=fwhm_weight_array_new)
            FWHM_estimation = numpy.median(fwhm_array_new)
            log.info('Final FWHM estimated is %.2f"' % FWHM_estimation)

        if len(fwhm_array) > 0:
            return FWHM_estimation, len(fwhm_array_new)
        else:
            return FWHM_estimation, None
コード例 #8
0
    def return_sources(self,
                       data,
                       camera,
                       maxp=50000.,
                       nplot=1000,
                       background=None,
                       noise=None,
                       sources=None,
                       model='simp',
                       det_sigma=5.0,
                       base_fwhm=8.0,
                       plot_stuff=False,
                       expid=None):
        '''
		plot light distribution for top ten sources
		'''
        log = logging.getLogger('star_sizes')
        from astropy.modeling import models, fitting
        if background == None or noise == None:
            log.debug("Finding background level...")
            mean, median, std = sigma_clipped_stats(data, sigma=5.0, iters=2)
            background = median
            noise = std
            #print(background, noise)
        global cic_count
        global cis_count
        global cin_count
        global ciw_count
        global cie_count
        # Detect sources
        #print('base fwhm'+str(base_fwhm))
        if sources == None:
            log.debug("Detecting sources..")
            daofind = DAOStarFinder(fwhm=base_fwhm,
                                    threshold=det_sigma * noise)
            sources = daofind(data - background)
            #print('found '+str(len(sources))+' sources')
        # Sort by SN
        w = sources['peak'] < maxp
        sources = sources[w]
        sources.sort('flux')
        sources.reverse()

        fwhm_array = []
        fwhm_weight_array = []
        x_coord = []
        y_coord = []
        final_func_val = []
        if len(sources) > nplot:
            sources = sources[:nplot]
        #print(len(sources))
        model_init = models.Gaussian1D(amplitude=1.0, mean=0, stddev=base_fwhm)

        for isource in sources:

            flux_counts = []
            pixel_distance = []
            npix = 0

            x_cen = int(isource['xcentroid'])
            y_cen = int(isource['ycentroid'])
            ##print(x_cen,y_cen)
            analysis_radius = 20
            #print(isource['peak'])
            try:
                for x in range(x_cen - analysis_radius,
                               x_cen + analysis_radius):
                    for y in range(y_cen - analysis_radius,
                                   y_cen + analysis_radius):
                        #flux_counts.append((data[y][x] - 0.) / isource['peak'])
                        val = (data[y][x] - background) / isource['peak']

                        flux_counts.append(val)
                        dis = numpy.linalg.norm((isource['xcentroid'] - x,
                                                 isource['ycentroid'] - y))
                        pixel_distance.append(dis)

                flux_counts = np.array(flux_counts)
                pixel_distance = np.array(pixel_distance)

                w = (flux_counts > 0.5)  #& (flux_counts < 0.65)
                psel = pixel_distance[w]
                fsel = flux_counts[w]
                mpsel = np.mean(psel)
                wn = psel < 2. * mpsel
                psel = psel[wn]
                fsel = fsel[wn]
                #A = np.vstack([fsel, np.ones(len(psel))]).T
                #m, c = np.linalg.lstsq(A, psel, rcond=None)[0]
                #ssq = sum((psel-m*fsel+c)**2.)/float(len(psel))
                fitter = fitting.SimplexLSQFitter()
                fitted_model = fitter(model_init, psel, fsel)

                iFWHM = 2.355 * fitted_model.stddev * self.pix_scale * self.micron_to_seeing[
                    camera]
                x_coord.append(x_cen)
                y_coord.append(y_cen)
                fwhm_array.append(iFWHM)
                final_func_val.append(fitter.fit_info['final_func_val'])
                #print(np.mean(psel),m*.5+c,ssq,iFWHM,fitter.fit_info['final_func_val'])

                #fo.write(str(x_cen)+' '+str(y_cen)+' '+str(iFWHM)+ ' '+str(fitter.fit_info['final_func_val'])+' '+str(isource['peak'])+'\n')
                #plt.plot(pixel_distance,flux_counts,'k-')
                #plt.plot(psel,fsel,'ro')
                #plt.show()
            except:
                #print('hit edge?')
                pass

        #fo.close()
        return np.array(x_coord), np.array(y_coord), np.array(
            fwhm_array), np.array(final_func_val)
コード例 #9
0
ファイル: continuum.py プロジェクト: caridlin/CWITools
def psfSubtract(fits,
                pos,
                redshift=None,
                vwindow=1000,
                radius=5,
                mode='scale2D',
                errLimit=3,
                inst='PCWI'):
    global lines, skylines

    ##### EXTRACT DATA FROM FITS
    data = fits[0].data  #data cube
    head = fits[0].header  #header

    #ROTATE (TEMPORARILY) SO THAT AXIS 2 IS 'IN-SLICE' for KCWI DATA
    if instrument == 'KCWI':
        data_rot = np.zeros((data.shape[0], data.shape[2], data.shape[1]))
        for wi in range(len(data)):
            data_rot[wi] = np.rot90(data[wi], k=1)
        data = data_rot
        pos = (pos[1], pos[0])

    w, y, x = data.shape  #Cube dimensions
    X = np.arange(x)  #Create domains X,Y and W
    Y = np.arange(y)
    W = np.array([
        head["CRVAL3"] + head["CD3_3"] * (i - head["CRPIX3"]) for i in range(w)
    ])

    ##### CREATE USEFUl VARIABLES & DATA STRUCTURES
    cmodel = np.zeros_like(data)  #Cube to store 3D continuum model
    usewav = np.ones_like(
        W, dtype=bool
    )  #Boolean array for whether or not to use wavelengths in fitting
    Xs = np.linspace(X[0], X[-1],
                     10 * x)  #Smooth X-Y domains for PSF modelling
    Ys = np.linspace(Y[0], Y[-1], 10 * y)
    ydist = 3600 * np.sqrt(
        np.cos(head["CRVAL2"] * np.pi / 180) * head["CD1_2"]**2 +
        head["CD2_2"]**2)  #X & Y pixel sizes in arcseconds
    xdist = 3600 * np.sqrt(
        np.cos(head["CRVAL2"] * np.pi / 180) * head["CD1_1"]**2 +
        head["CD2_1"]**2)
    ry = int(round(radius / ydist))  #X and Y 'radius' extent in pixels
    rx = int(round(radius / xdist))

    ##### EXCLUDE EMISSION LINE WAVELENGTHS
    usewav[W < head["WAVGOOD0"]] = 0
    usewav[W > head["WAVGOOD1"]] = 0
    if redshift != None:
        for line in lines:
            wc = (redshift + 1) * line
            dw = (vwindow * 1e5 / 3e10) * wc
            a, b = params.getband(wc - dw, wc + dw, head)
            usewav[a:b] = 0

    ##### OPTIMIZE CENTROID

    xc, yc = pos  #Take input position tuple

    x0, x1 = max(0, xc - rx), min(x,
                                  xc + rx + 1)  #Get bounding box for PSF fit
    y0, y1 = max(0, yc - ry), min(y, yc + ry + 1)

    img = np.sum(data[usewav, y0:y1, x0:x1], axis=0)  #Create white light image

    xdomain, xdata = range(x1 - x0), np.sum(
        img, axis=0)  #Get X and Y PSF profiles/domains
    ydomain, ydata = range(y1 - y0), np.sum(img, axis=1)

    fit = fitting.SimplexLSQFitter()  #Get astropy fitter class

    moffat_bounds = {'amplitude': (0, float("inf"))}
    xMoffInit = models.Moffat1D(max(xdata), x_0=xc - x0,
                                bounds=moffat_bounds)  #Initial guesses
    yMoffInit = models.Moffat1D(max(ydata), x_0=yc - y0, bounds=moffat_bounds)

    xMoffFit = fit(xMoffInit, xdomain, xdata)  #Fit Moffat1Ds to each axis
    yMoffFit = fit(yMoffInit, ydomain, ydata)

    xc_new = xMoffFit.x_0.value + x0
    yc_new = yMoffFit.x_0.value + y0

    #If the new centroid is beyond our anticipated error range away... just use scale method
    if abs(xc - xc_new) * xdist > errLimit or abs(yc -
                                                  yc_new) * ydist > errLimit:
        mode = 'scale2D'

        #Otherwise, update the box to center better on our continuum source
    else:
        xc, yc = int(round(xc_new)), int(
            round(yc_new))  #Round to nearest integer
        x0, x1 = max(0, xc - rx), min(x, xc + rx + 1)  #Get new ranges
        y0, y1 = max(0, yc - ry), min(y, yc + ry + 1)
        xc = max(0, min(x - 1, xc))  #Bound new variables to within image
        yc = max(0, min(y - 1, yc))

    #This method creates a 2D continuum image and scales it at each wavelength.
    if mode == 'scale2D':

        print 'scale2D',

        ##### CREATE CROPPED CUBE
        cube = data[:, y0:y1, x0:x1].copy(
        )  #Create smaller working cube to isolate continuum source

        ##### CREATE 2D CONTINUUM IMAGE
        cont2d = np.mean(cube[usewav], axis=0)  #Create 2D continuum image

        fitter = fitting.LinearLSQFitter()

        ##### BUILD 3D CONTINUUM MODEL
        for i in range(cube.shape[0]):

            A0 = max(0,
                     float(np.sum(cube[i])) /
                     np.sum(cont2d))  #Initial guess for scaling factor

            scale_init = models.Scale()

            scale_fit = fitter(scale_init, np.ndarray.flatten(cont2d),
                               np.ndarray.flatten(cube[i]))

            model = scale_fit.factor.value * cont2d  #Add this wavelength layer to the model

            data[i, y0:y1, x0:x1] -= model  #Subtract from data cube

            cmodel[i, y0:y1, x0:x1] += model  #Add to larger model cube

    #This method just fits a simple line to the spectrum each spaxel; for flat continuum sources.
    elif mode == 'lineFit':

        print 'lineFit',
        #Define custom astropy model class (just a line)
        @custom_model
        def line(xx, m=0, c=0):
            return m * xx + c

        #Run through pixels in 2D region
        for yi in range(y0, y1):
            for xi in range(x0, x1):

                m_init = line()  #Create initial guess model
                m = fit(m_init, W[usewav], data[usewav, yi,
                                                xi])  #Optimize model

                model = m(W)

                cmodel[:, yi, xi] += model
                data[:, yi, xi] -= model

    #This method extracts a central spectrum and fits it to each spaxel
    elif mode == 'specFit':

        print 'specFit',
        #Define custom astropy model class (just a line)
        @custom_model
        def line(xx, m=0, c=0):
            return m * xx + c

        ##### GET QSO SPECTRUM
        q_spec = data[:, yc, xc].copy()
        q_spec_fit = q_spec[usewav == 1]

        #Run through slices
        for yi in range(y0, y1):

            print yi,
            sys.stdout.flush()

            #If this not the main QSO slice
            if yi != yc:

                #Extract QSO spectrum for this slice
                s_spec = data[:, yi, xc].copy()
                s_spec_fit = s_spec[usewav == 1]

                #Estimate wavelength shift needed
                corr = scipy.signal.correlate(s_spec, q_spec)
                corrs = scipy.ndimage.filters.gaussian_filter1d(corr, 5.0)
                w_offset = (np.nanargmax(corrs) - len(corrs) / 2) / 2.0

                #Find wavelength offset (px) for this slice
                chisq = lambda x: s_spec_fit[10:-10] - x[
                    0] * scipy.ndimage.interpolation.shift(
                        q_spec_fit, x[1], order=4, mode='reflect')[10:-10]

                p0 = [np.max(s_spec) / np.max(q_spec), w_offset]

                lbound = [0.0, -5]
                ubound = [5.1, 5]
                for j in range(len(p0)):
                    if p0[j] < lbound[j]: p0[j] = lbound[j]
                    elif p0[j] > ubound[j]: p0[j] = ubound[j]

                p_fit = scipy.optimize.least_squares(chisq,
                                                     p0,
                                                     bounds=(lbound, ubound),
                                                     jac='3-point')

                A0, dw0 = p_fit.x

                q_spec_shifted = scipy.ndimage.interpolation.shift(
                    q_spec_fit, dw0, order=3, mode='reflect')

            else:
                q_spec_shifted = q_spec_fit
                A0 = 0.5
                dw0 = 0

            lbound = [0.0, -5]
            ubound = [20.0, 5]

            for xi in range(x0, x1):

                spec = data[:, yi, xi]
                spec_fit = spec[usewav == 1]

                #First fit to find wav offset for this slice
                chisq = lambda x: spec_fit - x[
                    0] * scipy.ndimage.interpolation.shift(
                        q_spec_fit, x[1], order=3, mode='reflect')

                p0 = [A0, dw0]
                for j in range(len(p0)):
                    if p0[j] < lbound[j]: p0[j] = lbound[j]
                    elif p0[j] > ubound[j]: p0[j] = ubound[j]
                    #elif abs(p0[j]<1e-6): p0[j]=0

                sys.stdout.flush()
                p_fit = scipy.optimize.least_squares(chisq,
                                                     p0,
                                                     bounds=(lbound, ubound),
                                                     jac='3-point')

                A, dw = p_fit.x

                m_spec = A * scipy.ndimage.interpolation.shift(
                    q_spec, dw, order=4, mode='reflect')

                #Do a linear fit to residual and correct linear errors
                residual = data[:, yi, xi] - m_spec

                ydata = residual[usewav == 1]
                xdata = W[usewav == 1]

                #m_init = line() #Create initial guess model
                #m = fit(m_init, xdata, ydata) #Optimize model

                #linefit = m(W)

                model = m_spec
                #residual = data[:,yi,xi] - model

                if 0 and abs(yi - yc) < 1 and abs(xi - xc) < 1:

                    plt.figure(figsize=(16, 8))

                    plt.subplot(311)
                    plt.title(r"$A=%.4f,d\lambda=%.3fpx$" % (A, dw))
                    plt.plot(W, spec, 'bx', alpha=0.5)
                    plt.plot(W[usewav == 1], spec[usewav == 1], 'kx')
                    plt.plot(W, A * q_spec, 'g-', alpha=0.8)
                    plt.plot(W, model, 'r-')
                    plt.xlim([W[0], W[-1]])
                    plt.ylim([1.5 * min(spec), max(spec) * 1.5])
                    plt.subplot(312)
                    plt.xlim([W[0], W[-1]])

                    plt.plot(W, residual, 'gx')
                    plt.ylim([1.5 * min(residual), max(spec) * 1.5])

                    plt.subplot(313)
                    plt.hist(residual)

                    plt.tight_layout()
                    plt.show()

                cmodel[:, yi, xi] += model
                data[:, yi, xi] -= model
    #ROTATE BACK IF ROTATED AT START
    if instrument == 'KCWI':
        data_rot = np.zeros((data.shape[0], data.shape[2], data.shape[1]))
        cmodel_rot = np.zeros((data.shape[0], data.shape[2], data.shape[1]))
        for wi in range(len(data)):
            data_rot[wi] = np.rot90(data[wi], k=3)
            cmodel_rot[wi] = np.rot90(cmodel[wi], k=3)
        data = data_rot
        cmodel = cmodel_rot

    return data, cmodel
コード例 #10
0
def get_mask(fits, regfile):

    print "\tGenerating 2D mask from region file"

    #EXTRACT/CREATE USEFUL VARS############
    data3D = fits[0].data
    head3D = fits[0].header

    W, Y, X = data3D.shape  #Dimensions
    mask = np.zeros((Y, X), dtype=int)  #Mask to be filled in
    x, y = np.arange(X), np.arange(Y)  #Create X/Y image coordinate domains
    xx, yy = np.meshgrid(x, y)  #Create meshgrid of X, Y
    ww = np.array([
        head3D["CRVAL3"] + head3D["CD3_3"] * (i - head3D["CRPIX3"])
        for i in range(W)
    ])

    yPS = np.sqrt(
        np.cos(head3D["CRVAL2"] * np.pi / 180) * head3D["CD1_2"]**2 +
        head3D["CD2_2"]**2)  #X & Y plate scales (deg/px)
    xPS = np.sqrt(
        np.cos(head3D["CRVAL2"] * np.pi / 180) * head3D["CD1_1"]**2 +
        head3D["CD2_1"]**2)

    fit = fitting.SimplexLSQFitter()  #Get astropy fitter class
    Lfit = fitting.LinearLSQFitter()

    usewav = np.ones_like(ww, dtype=bool)
    usewav[ww < head3D["WAVGOOD0"]] = 0
    usewav[ww > head3D["WAVGOOD1"]] = 0

    data2D = np.sum(data3D[usewav], axis=0)
    med = np.median(data2D)

    #BUILD MASK############################
    if regfile[0].coord_format == 'image':

        rr = np.sqrt((xx - x0)**2 + (yy - y0)**2)
        mask[rr <= R] = i + 1

    elif regfile[0].coord_format == 'fk5':

        #AIC = 2k + n Log(RSS/n) [ - (2k**2 +2k )/(n-k-1) ]
        def AICc(dat, mod, k):
            RSS = np.sum((dat - mod)**2)
            n = np.size(dat)
            return 2 * k + n * np.log(RSS / n)  #+ (2*k**2 + 2*k)/(n-k-1)

        head2D = head3D.copy()  #Create a 2D header by modifying 3D header
        for key in [
                "NAXIS3", "CRPIX3", "CD3_3", "CRVAL3", "CTYPE3", "CNAME3",
                "CUNIT3"
        ]:
            head2D.remove(key)
        head2D["NAXIS"] = 2
        head2D["WCSDIM"] = 2
        wcs = WCS(head2D)
        ra, dec = wcs.wcs_pix2world(xx, yy, 0)  #Get meshes of RA/DEC

        for i, reg in enumerate(regfile):

            ra0, dec0, R = reg.coord_list  #Extract location and default radius
            rr = np.sqrt(
                (np.cos(dec * np.pi / 180) * (ra - ra0))**2 +
                (dec - dec0)**2)  #Create meshgrid of distance to source

            if np.min(rr) > R:
                continue  #Skip any sources more than one default radius outside the FOV

            else:

                yc, xc = np.where(rr == np.min(rr))  #Take input position tuple
                xc, yc = xc[0], yc[0]

                rx = 2 * int(round(
                    R / xPS))  #Convert angular radius to distance in pixels
                ry = 2 * int(round(R / yPS))

                x0, x1 = max(0, xc - rx), min(X, xc + rx +
                                              1)  #Get bounding box for PSF fit
                y0, y1 = max(0, yc - ry), min(Y, yc + ry + 1)

                img = np.mean(data3D[usewav, y0:y1, x0:x1],
                              axis=0)  #Not strictly a white-light image
                img -= np.median(img)  #Correct in case of bad sky subtraction

                xdomain, xdata = range(x1 - x0), np.mean(
                    img, axis=0)  #Get X and Y domains/data
                ydomain, ydata = range(y1 - y0), np.mean(img, axis=1)

                moffat_bounds = {'amplitude': (0, float("inf"))}
                xMoffInit = models.Moffat1D(
                    max(xdata), x_0=xc - x0,
                    bounds=moffat_bounds)  #Initial guess Moffat profiles
                yMoffInit = models.Moffat1D(max(ydata),
                                            x_0=yc - y0,
                                            bounds=moffat_bounds)
                xLineInit = models.Linear1D(slope=0, intercept=np.mean(xdata))
                yLineInit = models.Linear1D(slope=0, intercept=np.mean(ydata))

                xMoffFit = fit(xMoffInit, xdomain,
                               xdata)  #Fit Moffat1Ds to each axis
                yMoffFit = fit(yMoffInit, ydomain, ydata)
                xLineFit = Lfit(xLineInit, xdomain,
                                xdata)  #Fit Linear1Ds to each axis
                yLineFit = Lfit(yLineInit, ydomain, ydata)

                kMoff = len(xMoffFit.parameters
                            )  #Get number of parameters in each model
                kLine = len(xLineFit.parameters)

                xMoffAICc = AICc(
                    xdata, xMoffFit(xdomain),
                    kMoff)  #Get Akaike Information Criterion for each
                xLineAICc = AICc(xdata, xLineFit(xdomain), kLine)
                yMoffAICc = AICc(ydata, yMoffFit(ydomain), kMoff)
                yLineAICc = AICc(ydata, yLineFit(ydomain), kLine)

                xIsMoff = xMoffAICc < xLineAICc  # Determine if Moffat is a better fit than a simple line
                yIsMoff = yMoffAICc < yLineAICc

                if xIsMoff and yIsMoff:  #If source has detectable moffat profile (i.e. bright source) expand mask

                    xfwhm = xMoffFit.gamma.value * 2 * np.sqrt(
                        2**(1 / xMoffFit.alpha.value) - 1)  #Get FWHMs
                    yfwhm = yMoffFit.gamma.value * 2 * np.sqrt(
                        2**(1 / yMoffFit.alpha.value) - 1)

                    R = 2 * max(xfwhm * xPS, yfwhm * yPS)

                mask[rr < R] = i + 1

    return mask
コード例 #11
0
    uv_mean_structure_function = np.loadtxt(
        f'sf_data/uv/structure_function_most_recent')[2:]
    uv_std_structure_function = np.loadtxt(
        f'sf_data/uv/errors_most_recent')[2:]

    # Fit the GP UVW2 structure functions using a power law or broken power law
    power_law_model = PowerLaw1D()
    if kernel == 'RQ':
        broken_power_law_model = BrokenPowerLaw1D(alpha_1=0,
                                                  alpha_2=0,
                                                  x_break=110)
    else:
        broken_power_law_model = BrokenPowerLaw1D(alpha_1=-1,
                                                  alpha_2=0,
                                                  x_break=110)
    fitter_plm = fitting.SimplexLSQFitter()
    power_law_tao_vals = uv_gp_tao_plot
    uv_gp_mean_structure_function *= 1e29  # multiply by a large number to prevent error in fitting power laws.
    uv_gp_std_structure_function *= 1e29
    power_law_sf_vals = uv_gp_mean_structure_function

    # Large number of iterations required for optimiser convergence (maxiter argument)
    # Use uncertainties to improve the fit as per this tutorial:
    # https://docs.astropy.org/en/stable/modeling/example-fitting-line.html#fit-using-uncertainties

    plm = fitter_plm(broken_power_law_model,
                     power_law_tao_vals,
                     power_law_sf_vals,
                     weights=1 / uv_gp_std_structure_function,
                     maxiter=5000)
コード例 #12
0
def fit_models(input_model: Fittable2DModel,
               pixelphase=0.,
               n_sources=4,
               img_size=128,
               img_border=16,
               σ=0,
               λ=None,
               fitshape=(7, 7),
               model_oversampling=2,
               model_degree=5,
               model_mode='grid',
               fit_accuracy=1e-8,
               use_weights=True,
               fitter_name='LM',
               return_imgs=False,
               fit_bounds=None,
               seed=0) -> dict:

    rng = np.random.default_rng(seed)

    if fitter_name == 'LM':
        iter_name = 'nfev'
        fitter = fitting.LevMarLSQFitter()
    elif fitter_name == 'Simplex':
        iter_name = 'numiter'
        fitter = fitting.SimplexLSQFitter()
    else:
        raise NotImplementedError

    fitshape = np.array(fitshape)
    img, xy_sources = gen_image(input_model, n_sources, img_size, img_border, pixelphase, σ, λ, rng)

    fit_model = make_fit_model(input_model, model_mode, fitshape, model_degree, model_oversampling)

    y_grid, x_grid = np.indices(img.shape)

    res = np.full((len(xy_sources), 7), np.nan)
    residual = img.copy()

    for i, xy_position in enumerate(xy_sources):

        fitted = fit_single_image(fit_model,
                                  img,
                                  x_grid,
                                  y_grid,
                                  xy_position,
                                  fitter,
                                  fitshape,
                                  σ,
                                  λ,
                                  fit_accuracy,
                                  use_weights,
                                  fit_bounds,
                                  rng)

        res[i] = (xy_position[0], xy_position[1],
                  fitted.x.value, fitted.y.value,
                  fitted.flux.value, fitted.snr,
                  fitter.fit_info[iter_name])
        residual -= fitted(x_grid, y_grid)

    x_dev = res[:, 0] - res[:, 2]
    y_dev = res[:, 1] - res[:, 3]
    dev = np.sqrt(x_dev**2 + y_dev**2)
    ret = {'x':    res[:, 0], 'y': res[:, 1],
           'dev':  dev, 'x_dev': x_dev, 'y_dev': y_dev,
           'flux': res[:, 4], 'snr': res[:, 5],
           'fititers': res[:, 6], 'peak_flux': np.max(img)}
    if return_imgs:
        ret |= {'img': img, 'residual': residual}

    return ret