def shell_model(major=50, minor=40, ratio=1.25, amp=0.5, pa=0, xcent=0, ycent=0, ring_large=None, ring_small=[40, 32]): ''' Difference of Gaussians with the middle clipped to the background. ''' gauss_model = \ Gaussian2D(shell_max(amp, minor, ratio), xcent, ycent, ratio*major, ratio*minor, theta=pa) - \ Gaussian2D(shell_max(amp, minor, ratio), xcent, ycent, major, minor, theta=pa) if ring_large is None and ring_small is None: return gauss_model elif ring_small is None and ring_large is not None: ring = Ellipse2D(True, xcent, ycent, ring_large[0], ring_large[1], pa) elif ring_small is not None and ring_large is None: ring = InvertedEllipse2D(True, xcent, ycent, ring_small[0], ring_small[1], pa) else: ring = \ Ellipse2D(True, xcent, ycent, ring_large[0], ring_large[1], pa) - \ Ellipse2D(True, xcent, ycent, ring_small[0], ring_small[1], pa) return gauss_model * ring
def test_bounding_box(): g = Gaussian2D() + Gaussian2D(2, .5, .1, 2, 3, 0) g.bounding_box = ((0, 1), (0, .5)) y, x = np.mgrid[0:10, 0:10] y = y / 3. x = x / 3. val = g(x, y, with_bounding_box=True) compare = np.array([ [2.93738984, 2.93792011, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [2.87857153, 2.88188761, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [2.70492922, 2.71529265, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [2.45969972, 2.47912103, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]]) mask = ~np.isnan(val) assert_allclose(val[mask], compare[mask]) val2 = g(x+2, y+2, with_bounding_box=True) assert np.isnan(val2).sum() == 100
def prf_model(request): # use this instead of pytest.mark.parameterize as we use scipy and # it still calls that even if not HAS_SCIPY is set... prfs = [ IntegratedGaussianPRF(sigma=1.2), Gaussian2D(x_stddev=2), prepare_psf_model(Gaussian2D(x_stddev=2), renormalize_psf=False) ] return prfs[request.param]
def test_deblend_multiple_sources_with_neighbor(self): g1 = Gaussian2D(100, 50, 50, 20, 5, theta=45) g2 = Gaussian2D(100, 35, 50, 5, 5) g3 = Gaussian2D(100, 60, 20, 5, 5) x = self.x y = self.y data = (g1 + g2 + g3)(x, y) segm = detect_sources(data, self.threshold, self.npixels) result = deblend_sources(data, segm, self.npixels) assert result.nlabels == 3
def setup_class(self): g1 = Gaussian2D(100, 50, 50, 5, 5) g2 = Gaussian2D(100, 35, 50, 5, 5) g3 = Gaussian2D(30, 70, 50, 5, 5) y, x = np.mgrid[0:100, 0:100] self.x = x self.y = y self.data = g1(x, y) + g2(x, y) self.data3 = self.data + g3(x, y) self.threshold = 10 self.npixels = 5 self.segm = detect_sources(self.data, self.threshold, self.npixels) self.segm3 = detect_sources(self.data3, self.threshold, self.npixels)
def test_fix_inputs(): g1 = Gaussian2D(1, 0, 0, 1, 2) g2 = Gaussian2D(1.5, .5, -.2, .5, .3) sg1_1 = fix_inputs(g1, {1: 0}) assert_allclose(sg1_1(0), g1(0, 0)) assert_allclose(sg1_1([0, 1, 3]), g1([0, 1, 3], [0, 0, 0])) sg1_2 = fix_inputs(g1, {'x': 1}) assert_allclose(sg1_2(1.5), g1(1, 1.5)) gg1 = g1 & g2 sgg1_1 = fix_inputs(gg1, {1: 0.1, 3: 0.2}) assert_allclose(sgg1_1(0, 0), gg1(0, 0.1, 0, 0.2)) sgg1_2 = fix_inputs(gg1, {'x0': -.1, 2: .1}) assert_allclose(sgg1_2(1, 1), gg1(-0.1, 1, 0.1, 1)) assert_allclose(sgg1_2(y0=1, y1=1), gg1(-0.1, 1, 0.1, 1))
def test_deblend_label_assignment(self): """ Regression test to ensure newly-deblended labels are unique. """ y, x = np.mgrid[0:201, 0:101] y0a = 35 y1a = 60 yshift = 100 y0b = y0a + yshift y1b = y1a + yshift data = (Gaussian2D(80, 36, y0a, 8, 8)(x, y) + Gaussian2D(71, 58, y1a, 8, 8)(x, y) + Gaussian2D(30, 36, y1a, 7, 7)(x, y) + Gaussian2D(30, 58, y0a, 7, 7)(x, y) + Gaussian2D(80, 36, y0b, 8, 8)(x, y) + Gaussian2D(71, 58, y1b, 8, 8)(x, y) + Gaussian2D(30, 36, y1b, 7, 7)(x, y) + Gaussian2D(30, 58, y0b, 7, 7)(x, y)) npixels = 5 segm1 = detect_sources(data, 5.0, npixels) segm2 = deblend_sources(data, segm1, npixels, mode='linear', nlevels=32, contrast=0.3) assert segm2.nlabels == 4
def evaluate(x, y, amplitude1, x_stddev1, y_stddev1, amplitude2, x_stddev2, y_stddev2, amplitude3, x_stddev3, y_stddev3, x_mean, y_mean, theta, offset): g1 = Gaussian2D(amplitude=amplitude1, x_mean=x_mean, y_mean=y_mean, x_stddev=x_stddev1, y_stddev=y_stddev1, theta=theta) g1.amplitude.min = 0 g2 = Gaussian2D(amplitude=amplitude2, x_mean=x_mean, y_mean=y_mean, x_stddev=x_stddev2, y_stddev=y_stddev2, theta=theta) g2.amplitude.min = 0 g3 = Gaussian2D(amplitude=amplitude3, x_mean=x_mean, y_mean=y_mean, x_stddev=x_stddev3, y_stddev=y_stddev3, theta=theta) g3.amplitude.min = 0 y1 = g1.evaluate(x, y, amplitude=amplitude1, x_mean=x_mean, y_mean=y_mean, x_stddev=x_stddev1, y_stddev=y_stddev1, theta=theta) y2 = g2.evaluate(x, y, amplitude=amplitude2, x_mean=x_mean, y_mean=y_mean, x_stddev=x_stddev2, y_stddev=y_stddev2, theta=theta) y3 = g3.evaluate(x, y, amplitude=amplitude3, x_mean=x_mean, y_mean=y_mean, x_stddev=x_stddev3, y_stddev=y_stddev3, theta=theta) return y1 + y2 + y3 + offset
def spatial_model(self, emin=1 * u.TeV, emax=10 * u.TeV): """ Source spatial model. """ d = self.data morph_type = d['morph_type'] pars = {} flux = self.spectral_model.integral(emin, emax) glon = Angle(d['glon']).wrap_at('180d') glat = Angle(d['glat']).wrap_at('180d') if morph_type == 'gauss': pars['x_mean'] = glon.value pars['y_mean'] = glat.value pars['x_stddev'] = d['morph_sigma'].value pars['y_stddev'] = d['morph_sigma'].value if not np.isnan(d['morph_sigma2']): pars['y_stddev'] = d['morph_sigma2'].value if not np.isnan(d['morph_pa']): # TODO: handle reference frame for rotation angle pars['theta'] = Angle(d['morph_pa'], 'deg').rad ampl = flux.to('cm-2 s-1').value pars['amplitude'] = ampl * 1 / (2 * np.pi * pars['x_stddev'] * pars['y_stddev']) return Gaussian2D(**pars) elif morph_type == 'shell': pars['amplitude'] = flux.to('cm-2 s-1').value pars['x_0'] = glon.value pars['y_0'] = glat.value pars['r_in'] = d['morph_sigma'].value * 0.8 pars['width'] = 0.2 * d['morph_sigma'].value return Shell2D(**pars) elif morph_type == 'point': DEFAULT_POINT_EXTENSION = Angle('0.05 deg') pars['amplitude'] = flux.to('cm-2 s-1').value pars['x_mean'] = glon.value pars['y_mean'] = glat.value pars['x_stddev'] = DEFAULT_POINT_EXTENSION pars['y_stddev'] = DEFAULT_POINT_EXTENSION # TODO: make Delta2D work and use it here. return Gaussian2D(**pars) elif morph_type == 'none': raise NoDataAvailableError('No spatial model available: {}'.format( self.name)) else: raise NotImplementedError( 'Unknown spatial model: {!r}'.format(morph_type))
def _setup_model(self): """Setup a list of source models from an ``input_sherpa.cfg`` config file. """ self.source_models = [] # Read config file from astropy.extern.configobj.configobj import ConfigObj cfg = ConfigObj(self.cfg_file, file_error=True) # Set up model from astropy.modeling.models import Gaussian2D for source in cfg.keys(): # TODO: Add other source models if cfg[source]['Type'] != 'NormGaussian': raise ValueError( 'So far only normgauss2d models can be handled.') sigma = gaussian_fwhm_to_sigma * float(cfg[source]['fwhm']) ampl = float(cfg[source]['ampl']) * 1 / (2 * np.pi * sigma**2) xpos = float(cfg[source]['xpos']) - 1 ypos = float(cfg[source]['ypos']) - 1 source_model = Gaussian2D(ampl, xpos, ypos, x_stddev=sigma, y_stddev=sigma) self.source_models.append(source_model)
def __init__(self, stddev_maj, stddev_min, position_angle, support_scaling=8, **kwargs): self._model = Gaussian2D(1. / (2 * np.pi * stddev_maj * stddev_min), 0, 0, x_stddev=stddev_maj, y_stddev=stddev_min, theta=position_angle) try: from astropy.modeling.utils import ellipse_extent except ImportError: raise NotImplementedError("EllipticalGaussian2DKernel requires" " astropy 1.1b1 or greater.") max_extent = \ np.max(ellipse_extent(stddev_maj, stddev_min, position_angle)) self._default_size = \ _round_up_to_odd_integer(support_scaling * 2 * max_extent) super(EllipticalGaussian2DKernel, self).__init__(**kwargs) self._truncation = np.abs(1. - 1 / self._array.sum())
def test_image_model_oversampling(): gm = Gaussian2D(x_stddev=3, y_stddev=3) osa = 3 #oversampling factor xg, yg = np.mgrid[-3:3.00001:(1 / osa), -3:3.00001:(1 / osa)] im = gm(xg, yg) assert im.shape[ 0] > 7 # should be obvious, but at least ensures the test is right imod_oversampled = FittableImageModel(im, oversampling=osa) assert np.allclose(imod_oversampled(0, 0), gm(0, 0)) assert np.allclose(imod_oversampled(1, 1), gm(1, 1)) assert np.allclose(imod_oversampled(-2, 1), gm(-2, 1)) assert np.allclose(imod_oversampled(0.5, 0.5), gm(0.5, 0.5), rtol=.001) assert np.allclose(imod_oversampled(-0.5, 1.75), gm(-0.5, 1.75), rtol=.001) imod_wrongsampled = FittableImageModel(im) # now make sure that all *fails* without the oversampling assert np.allclose(imod_wrongsampled(0, 0), gm(0, 0)) # except for at the origin assert not np.allclose(imod_wrongsampled(1, 1), gm(1, 1)) assert not np.allclose(imod_wrongsampled(-2, 1), gm(-2, 1)) assert not np.allclose( imod_wrongsampled(0.5, 0.5), gm(0.5, 0.5), rtol=.001) assert not np.allclose( imod_wrongsampled(-0.5, 1.75), gm(-0.5, 1.75), rtol=.001)
def test_image_model(): gm = Gaussian2D(x_stddev=3, y_stddev=3) xg, yg = np.mgrid[-2:3, -2:3] imod_nonorm = FittableImageModel(gm(xg, yg)) assert np.allclose(imod_nonorm(0, 0), gm(0, 0)) assert np.allclose(imod_nonorm(1, 1), gm(1, 1)) assert np.allclose(imod_nonorm(-2, 1), gm(-2, 1)) # now sub-pixel should *not* match, but be reasonably close assert not np.allclose(imod_nonorm(0.5, 0.5), gm(0.5, 0.5)) # in this case good to ~0.1% seems to be fine assert np.allclose(imod_nonorm(0.5, 0.5), gm(0.5, 0.5), rtol=.001) assert np.allclose(imod_nonorm(-0.5, 1.75), gm(-0.5, 1.75), rtol=.001) imod_norm = FittableImageModel(gm(xg, yg), normalize=True) assert not np.allclose(imod_norm(0, 0), gm(0, 0)) assert np.allclose(np.sum(imod_norm(xg, yg)), 1) imod_norm2 = FittableImageModel(gm(xg, yg), normalize=True, normalization_correction=2) assert not np.allclose(imod_norm2(0, 0), gm(0, 0)) assert np.allclose(imod_norm(0, 0), imod_norm2(0, 0) * 2) assert np.allclose(np.sum(imod_norm2(xg, yg)), 0.5)
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 test_centroids_nan_withmask(use_mask): xc_ref = 24.7 yc_ref = 25.2 model = Gaussian2D(2.4, xc_ref, yc_ref, x_stddev=5.0, y_stddev=5.0) y, x = np.mgrid[0:50, 0:50] data = model(x, y) data[20, :] = np.nan if use_mask: mask = np.zeros(data.shape, dtype=bool) mask[20, :] = True nwarn = 0 else: mask = None nwarn = 1 with warnings.catch_warnings(record=True) as warnlist: xc, yc = centroid_1dg(data, mask=mask) assert_allclose([xc, yc], [xc_ref, yc_ref], rtol=0, atol=1.e-3) assert len(warnlist) == nwarn if nwarn == 1: assert issubclass(warnlist[0].category, AstropyUserWarning) with warnings.catch_warnings(record=True) as warnlist: xc, yc = centroid_2dg(data, mask=mask) assert_allclose([xc, yc], [xc_ref, yc_ref], rtol=0, atol=1.e-3) assert len(warnlist) == nwarn if nwarn == 1: assert issubclass(warnlist[0].category, AstropyUserWarning)
def __init__(self, function, shape, **kwargs): if not isinstance(shape, tuple): if isinstance(shape, int): shape = (shape, shape) self.shape = shape self.center = ((self.shape[0] + 1) / 2, (self.shape[1] + 1) / 2) if function == 'Gaussian': if 'radius' in kwargs: # Copying the radius keyword argument into the proper Gaussian2D keywords kwargs['x_stddev'] = kwargs['radius'] kwargs['y_stddev'] = kwargs['radius'] del kwargs['radius'] self.model = Gaussian2D(x_mean=self.center[0], y_mean=self.center[1], **kwargs) elif function == 'Airy': self.model = AiryDisk2D(x_0=self.center[0], y_0=self.center[1], **kwargs) else: raise ValueError( "Function value <{}> for Apodizer class is not recognized!". format(function))
def _make_gaussian_sources_image(self, table_bgstars, nsigma=6): "the one from photutils was too slow" image = np.zeros(self.image_shape_pix) for i in range(self.nstars_in_image): amplitude = table_bgstars['flux'][i] / ( 2. * np.pi * table_bgstars['x_stddev'][i] * table_bgstars['y_stddev'][i]) x_mean = table_bgstars['x_mean'][i] y_mean = table_bgstars['y_mean'][i] x_stddev = table_bgstars['x_stddev'][i] y_stddev = table_bgstars['y_stddev'][i] gmodel = Gaussian2D(amplitude=amplitude, x_mean=0, y_mean=0, x_stddev=x_stddev, y_stddev=y_stddev, theta=table_bgstars['theta'][i]) x_range = self._get_range(mean_val=x_mean, sigma=x_stddev, nsigma=nsigma, axis='x') y_range = self._get_range(mean_val=y_mean, sigma=y_stddev, nsigma=nsigma, axis='y') dmodel = discretize_model(model=gmodel, x_range=tuple(x_range - x_mean), y_range=tuple(y_range - y_mean), mode='oversample', factor=self.psf_oversample) image[int(x_range[0]):int(x_range[1]), int(y_range[0]):int(y_range[1])] += dmodel.T return image
def test_fix_inputs_invalid(): g1 = Gaussian2D(1, 0, 0, 1, 2) with pytest.raises(ValueError): fix_inputs(g1, {'x0': 0, 0: 0}) with pytest.raises(ValueError): fix_inputs(g1, (0, 1)) with pytest.raises(ValueError): fix_inputs(g1, {3: 2}) with pytest.raises(ValueError): fix_inputs(g1, {np.int32(3): 2}) with pytest.raises(ValueError): fix_inputs(g1, {np.int64(3): 2}) with pytest.raises(ValueError): fix_inputs(g1, {'w': 2}) with pytest.raises(ModelDefinitionError): CompoundModel('#', g1, g1) with pytest.raises(ValueError): gg1 = fix_inputs(g1, {0: 1}) gg1(2, y=2) with pytest.raises(ValueError): gg1 = fix_inputs(g1, {np.int32(0): 1}) gg1(2, y=2) with pytest.raises(ValueError): gg1 = fix_inputs(g1, {np.int64(0): 1}) gg1(2, y=2)
def __init__(self, type, shape=None, **kwargs): # Store input self.type = type self.shape = shape # Derive center of model shape if self.shape is None: self.center = (0, 0) else: self.center = ((self.shape[0] + 1) / 2, (self.shape[1] + 1) / 2) # Initialize model if 'gauss' in self.type.lower(): if 'radius' in kwargs: # Copying the radius keyword argument into the proper Gaussian2D keywords kwargs['x_stddev'] = kwargs['radius'] kwargs['y_stddev'] = kwargs['radius'] del kwargs['radius'] self.model = Gaussian2D(x_mean=self.center[0], y_mean=self.center[1], **kwargs) elif 'airy' in self.type.lower(): self.model = AiryDisk2D(x_0=self.center[0], y_0=self.center[1], **kwargs) else: raise SpecklepyValueError('PSFModel', argname='type', argvalue=type, expected="either 'Gaussian' or 'Airy'")
def gaussian_psf(self, xstd, ystd, theta, boxsize, scale): """ Gaussian PSF profile image Parameters ---------- xstd: float Standard deviation of the Gaussian in x before rotating by theta ystd: float Standard deviation of the Gaussian in y before rotating by theta theta: float Rotation angle in radians. The rotation angle increases counterclockwise boxsize: float Size of image on a side for Moffat profile scale: float Pixel scale for image Returns ------- zarray: numpy 3d array An array with length 3 for the first axis: PSF image, xgrid, ygrid """ M = Gaussian2D() M.x_stddev.value = xstd M.y_stddev.value = ystd M.theta.value = theta xl, xh = (0.0 - boxsize / 2.0, 0.0 + boxsize / 2.0 + scale) yl, yh = (0.0 - boxsize / 2.0, 0.0 + boxsize / 2.0 + scale) x, y = (np.arange(xl, xh, scale), np.arange(yl, yh, scale)) xgrid, ygrid = np.meshgrid(x, y) zarray = np.array([M(xgrid, ygrid), xgrid, ygrid]) zarray[0] /= zarray[0].sum() return zarray
def add_gaussian_holes(array, nholes=100, rad_max=30, rad_min=10, return_info=False, hole_level=None): ylim, xlim = array.shape yy, xx = np.mgrid[-ylim/2:ylim/2, -xlim/2:xlim/2] xcenters = np.random.random_integers(-(xlim/2-rad_max), high=xlim/2-rad_max, size=nholes) ycenters = np.random.random_integers(-(ylim/2-rad_max), high=ylim/2-rad_max, size=nholes) radii = np.random.random_integers(rad_min, rad_max, size=nholes) if hole_level is None: # Choose random hole bkg levels bkgs = np.random.uniform(0.5, 0.75, size=nholes) else: bkgs = np.array([hole_level] * nholes, dtype=np.int) for x, y, radius, amp in zip(xcenters, ycenters, radii, bkgs): gauss = Gaussian2D.evaluate(yy, xx, amp, x, y, radius, radius, 0.0) array -= gauss if return_info: return array, np.vstack([ycenters+ylim/2, xcenters+xlim/2, radii]) return array
def test_compound_evaluate_double_shift(): x = np.linspace(-5, 5, 10) y = np.linspace(-5, 5, 10) m1 = Gaussian2D(1, 0, 0, 1, 1, 1) m2 = Shift(1) m3 = Shift(2) m = Gaussian2D(1, 0, 0, 1, 1, 1) & Shift(1) & Shift(2) assert_array_equal( m.evaluate(x, y, x - 10, y + 20, 1, 0, 0, 1, 1, 1, 1, 2), [ m1.evaluate(x, y, 1, 0, 0, 1, 1, 1), m2.evaluate(x - 10, 1), m3.evaluate(y + 20, 2), ], )
def test_centroids(x_std, y_std, theta): model = Gaussian2D(2.4, XCEN, YCEN, x_stddev=x_std, y_stddev=y_std, theta=theta) y, x = np.mgrid[0:50, 0:47] data = model(x, y) xc, yc = centroid_1dg(data) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) xc, yc = centroid_2dg(data) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) # test with errors error = np.sqrt(data) xc, yc = centroid_1dg(data, error=error) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) xc, yc = centroid_2dg(data, error=error) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) # test with mask mask = np.zeros(data.shape, dtype=bool) data[10, 10] = 1.e5 mask[10, 10] = True xc, yc = centroid_1dg(data, mask=mask) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) xc, yc = centroid_2dg(data, mask=mask) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3)
def create_model(model_name, amplitude, center, sigma): """ This function ... :param model_name: :param amplitude: :param center: :param sigma: :return: """ # 2D GAussian model if model_name == "gaussian": # Create the model model = Gaussian2D(amplitude=amplitude, x_mean=center.x, y_mean=center.y, x_stddev=sigma, y_stddev=sigma) # Airy disk model elif model_name == "airydisk": # Determine the radius radius = fitting.gaussian_sigma_to_airy_radius(sigma) # Create the model model = AiryDisk2D(amplitude=amplitude, x_0=center.x, y_0=center.y, radius=radius) # Invalid else: raise ValueError("Not a valid model") # Return the model return model
def test_indexing_on_instance(): """Test indexing on compound model instances.""" m = Gaussian1D(1, 0, 0.1) + Const1D(2) assert isinstance(m[0], Gaussian1D) assert isinstance(m[1], Const1D) assert m.param_names == ('amplitude_0', 'mean_0', 'stddev_0', 'amplitude_1') # Test parameter equivalence assert m[0].amplitude == 1 == m.amplitude_0 assert m[0].mean == 0 == m.mean_0 assert m[0].stddev == 0.1 == m.stddev_0 assert m[1].amplitude == 2 == m.amplitude_1 # Test that parameter value updates are symmetric between the compound # model and the submodel returned by indexing const = m[1] m.amplitude_1 = 42 assert const.amplitude == 42 const.amplitude = 137 assert m.amplitude_1 == 137 # Similar couple of tests, but now where the compound model was created # from model instances g = Gaussian1D(1, 2, 3, name='g') p = Polynomial1D(2, name='p') m = g + p assert m[0].name == 'g' assert m[1].name == 'p' assert m['g'].name == 'g' assert m['p'].name == 'p' poly = m[1] m.c0_1 = 12345 assert poly.c0 == 12345 poly.c1 = 6789 assert m.c1_1 == 6789 # Test negative indexing assert isinstance(m[-1], Polynomial1D) assert isinstance(m[-2], Gaussian1D) with pytest.raises(IndexError): m[42] with pytest.raises(IndexError): m['foobar'] # Confirm index-by-name works with fix_inputs g = Gaussian2D(1, 2, 3, 4, 5, name='g') m = fix_inputs(g, {0: 1}) assert m['g'].name == 'g' # Test string slicing A = Const1D(1.1, name='A') B = Const1D(2.1, name='B') C = Const1D(3.1, name='C') M = A + B * C assert_allclose(M['B':'C'](1), 6.510000000000001)
def test_centroid_com_nan_withmask(use_mask): xc_ref = 24.7 yc_ref = 25.2 model = Gaussian2D(2.4, xc_ref, yc_ref, x_stddev=5.0, y_stddev=5.0) y, x = np.mgrid[0:50, 0:50] data = model(x, y) data[20, :] = np.nan if use_mask: mask = np.zeros(data.shape, dtype=bool) mask[20, :] = True nwarn = 0 ctx = nullcontext() else: mask = None nwarn = 1 ctx = pytest.warns(AstropyUserWarning, match='Input data contains non-finite values') with ctx as warnlist: xc, yc = centroid_com(data, mask=mask) assert_allclose(xc, xc_ref, rtol=0, atol=1.e-3) assert yc > yc_ref if nwarn == 1: assert len(warnlist) == nwarn with pytest.warns(AstropyUserWarning, match='Input data contains non-finite ' 'values') as warnlist: xc, yc = centroid_quadratic(data, mask=mask) assert_allclose(xc, xc_ref, rtol=0, atol=0.15) assert len(warnlist) == 1
def plot_gauss(x_loc, y_loc, S150, maj, min, PA): x_loc = int(round(x_loc)) y_loc = int(round(y_loc)) x_stddev = maj / (factor * reso * 3600.0) y_stddev = min / (factor * reso * 3600.0) gauss_func = Gaussian2D(amplitude=S150, x_mean=0, y_mean=0, x_stddev=x_stddev, y_stddev=y_stddev, theta=pi / 2 + PA * (pi / 180.0)) x_mesh, y_mesh = meshgrid( linspace(-edge_size, edge_size, edge_size * 2 + 1), linspace(-edge_size, edge_size, edge_size * 2 + 1)) gauss = gauss_func(x_mesh, y_mesh) gauss *= S150 / gauss.sum() sky[-edge_size + y_loc:edge_size + 1 + y_loc, -edge_size + x_loc:edge_size + 1 + x_loc] += gauss
def test_centroid_com(x_std, y_std, theta): model = Gaussian2D(2.4, XCEN, YCEN, x_stddev=x_std, y_stddev=y_std, theta=theta) y, x = np.mgrid[0:50, 0:47] data = model(x, y) xc, yc = centroid_com(data) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) xc, yc = centroid_quadratic(data) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=0.015) # test with mask mask = np.zeros(data.shape, dtype=bool) data[10, 10] = 1.e5 mask[10, 10] = True xc, yc = centroid_com(data, mask=mask) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=1.e-3) xc, yc = centroid_quadratic(data, mask=mask) assert_allclose((xc, yc), (XCEN, YCEN), rtol=0, atol=0.015) # test with oversampling for oversampling in [4, (4, 6)]: if not hasattr(oversampling, '__len__'): _oversampling = (oversampling, oversampling) else: _oversampling = oversampling xc, yc = centroid_com(data, mask=mask, oversampling=oversampling) desired = [XCEN / _oversampling[0], YCEN / _oversampling[1]] assert_allclose((xc, yc), desired, rtol=0, atol=1.e-3)
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 test_centroid_sources(): theta = np.pi / 6. model = Gaussian2D(2.4, XCEN, YCEN, x_stddev=3.2, y_stddev=5.7, theta=theta) y, x = np.mgrid[0:50, 0:47] data = model(x, y) error = np.ones(data.shape, dtype=float) mask = np.zeros(data.shape, dtype=bool) mask[10, 10] = True xpos = [25.] ypos = [26.] xc, yc = centroid_sources(data, xpos, ypos, box_size=21, mask=mask) assert_allclose(xc, (25.67,), atol=1e-1) assert_allclose(yc, (26.18,), atol=1e-1) xc, yc = centroid_sources(data, xpos, ypos, error=error, box_size=11, centroid_func=centroid_1dg) assert_allclose(xc, (25.67,), atol=1e-1) assert_allclose(yc, (26.41,), atol=1e-1) with pytest.raises(ValueError): centroid_sources(data, 25, [[26]], box_size=11) with pytest.raises(ValueError): centroid_sources(data, [[25]], 26, box_size=11) with pytest.raises(ValueError): centroid_sources(data, 25, 26, box_size=(1, 2, 3)) with pytest.raises(ValueError): centroid_sources(data, 25, 26, box_size=None, footprint=None) with pytest.raises(ValueError): centroid_sources(data, 25, 26, footprint=np.ones((3, 3, 3))) def test_func(data): return data with pytest.raises(ValueError): centroid_sources(data, [25], 26, centroid_func=test_func)
def add_gaussian_peaks(array, nholes=100, rad_max=30, rad_min=10): ylim, xlim = array.shape yy, xx = np.mgrid[-ylim/2:ylim/2, -xlim/2:xlim/2] xcenters = np.random.random_integers(-(xlim/2-rad_max), high=xlim/2-rad_max, size=nholes) ycenters = np.random.random_integers(-(ylim/2-rad_max), high=ylim/2-rad_max, size=nholes) radii = np.random.random_integers(rad_min, rad_max, size=nholes) for x, y, radius in zip(xcenters, ycenters, radii): amp = np.random.uniform(0.5, 0.75) gauss = Gaussian2D.evaluate(yy, xx, amp, x, y, radius, radius, 0.0) array += gauss return array