def applyRotation(self, theta): if not isinstance(theta, galsim.Angle): raise TypeError("Input theta should be an Angle") sigma = self.SBProfile.getSigma() bvec = self.SBProfile.getBVec().copy() bvec.rotate(theta) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def __setstate__(self, d): self.__dict__ = d psf_inv = galsim.Deconvolve(self.original_psf, gsparams=self._gsparams) GSObject.__init__( self, galsim.Convolve([self.original_gal, psf_inv], gsparams=self._gsparams))
def __init__(self, obj, gsparams=None): if not isinstance(obj, GSObject): raise TypeError("Argument to Deconvolve must be a GSObject.") GSObject.__init__(self, galsim.SBDeconvolve(obj.SBProfile, gsparams=gsparams)) if hasattr(obj,'noise'): import warnings warnings.warn("Unable to propagate noise in galsim.Deconvolve")
def __init__(self, obj, real_space=None, gsparams=None): if not isinstance(obj, GSObject): raise TypeError("Argument to AutoConvolve must be a GSObject.") # Check whether to perform real space convolution... # Start by checking if obj has a hard edge. hard_edge = obj.hasHardEdges() if real_space is None: # The automatic determination is to use real_space if obj has hard edges. real_space = hard_edge # Warn if doing DFT convolution for objects with hard edges. if not real_space and hard_edge: import warnings msg = """ Doing auto-convolution of object with hard edges. This might be more accurate and/or faster using real_space=True""" warnings.warn(msg) # Can't do real space if object is not analytic, so check for that. if real_space and not obj.isAnalyticX(): import warnings msg = """ Object to be auto-convolved is not analytic in real space. Cannot use real space convolution. Switching to DFT method.""" warnings.warn(msg) real_space = False GSObject.__init__(self, galsim.SBAutoConvolve(obj.SBProfile, real_space=real_space, gsparams=gsparams)) if hasattr(obj,'noise'): import warnings warnings.warn("Unable to propagate noise in galsim.AutoConvolve")
def __init__(self, *args, **kwargs): # Check kwargs first: gsparams = kwargs.pop("gsparams", None) # Make sure there is nothing left in the dict. if kwargs: raise TypeError( "Add constructor got unexpected keyword argument(s): %s"%kwargs.keys()) if len(args) == 0: # No arguments. Could initialize with an empty list but draw then segfaults. Raise an # exception instead. raise ValueError("Add must be initialized with at least one GSObject.") elif len(args) == 1: # 1 argument. Should be either a GSObject or a list of GSObjects if isinstance(args[0], GSObject): SBList = [args[0].SBProfile] elif isinstance(args[0], list): SBList = [] for obj in args[0]: if isinstance(obj, GSObject): SBList.append(obj.SBProfile) else: raise TypeError("Input list must contain only GSObjects.") else: raise TypeError("Single input argument must be a GSObject or list of them.") GSObject.__init__(self, galsim.SBAdd(SBList, gsparams=gsparams)) elif len(args) >= 2: # >= 2 arguments. Convert to a list of SBProfiles SBList = [obj.SBProfile for obj in args] GSObject.__init__(self, galsim.SBAdd(SBList, gsparams=gsparams))
def fitImage(self, image, center=None, normalization='flux'): """An obsolete method that is roughly equivalent to self = galsim.FitShapelet(self.sigma, self.order, image) """ new_obj = galsim.FitShapelet(self.sigma, self.order, image, center, normalization) bvec = new_obj.SBProfile.getBVec() GSObject.__init__(self, galsim._galsim.SBShapelet(self.sigma, bvec))
def __init__(self, real_kimage, imag_kimage, k_interpolant=None, stepk=None, gsparams=None): # make sure real_kimage, imag_kimage are really `Image`s, are floats, and are congruent. if not isinstance(real_kimage, galsim.Image) or not isinstance(imag_kimage, galsim.Image): raise ValueError("Supplied kimage is not an Image instance") if ((real_kimage.dtype != np.float32 and real_kimage.dtype != np.float64) or (imag_kimage.dtype != np.float32 and imag_kimage.dtype != np.float64)): raise ValueError("Supplied image does not have dtype of float32 or float64!") if real_kimage.bounds != imag_kimage.bounds: raise ValueError("Real and Imag kimages must have same bounds.") if real_kimage.scale != imag_kimage.scale: raise ValueError("Real and Imag kimages must have same scale.") # Make sure any `wcs`s are `PixelScale`s. if ((real_kimage.wcs is not None and not real_kimage.wcs.isPixelScale()) or (imag_kimage.wcs is not None and not imag_kimage.wcs.isPixelScale())): raise ValueError("Real and Imag kimage wcs's must be PixelScale's or None.") # Check for Hermitian symmetry properties of real_kimage and imag_kimage shape = real_kimage.array.shape # If image is even-sized, ignore first row/column since in this case not every pixel has # a symmetric partner to which to compare. bd = galsim.BoundsI(real_kimage.xmin + (1 if shape[1]%2==0 else 0), real_kimage.xmax, real_kimage.ymin + (1 if shape[0]%2==0 else 0), real_kimage.ymax) if not (np.allclose(real_kimage[bd].array, real_kimage[bd].array[::-1,::-1]) or np.allclose(imag_kimage[bd].array, -imag_kimage[bd].array[::-1,::-1])): raise ValueError("Real and Imag kimages must form a Hermitian complex matrix.") if stepk is None: stepk = real_kimage.scale else: if stepk < real_kimage.scale: import warnings warnings.warn( "Provided stepk is smaller than kimage.scale; overriding with kimage.scale.") stepk = real_kimage.scale self._real_kimage = real_kimage self._imag_kimage = imag_kimage self._stepk = stepk self._gsparams = gsparams # set up k_interpolant if none was provided by user, or check that the user-provided one # is of a valid type if k_interpolant is None: self.k_interpolant = galsim.Quintic(tol=1e-4) else: self.k_interpolant = galsim.utilities.convert_interpolant(k_interpolant) GSObject.__init__(self, galsim._galsim.SBInterpolatedKImage( self._real_kimage.image, self._imag_kimage.image, self._real_kimage.scale, self._stepk, self.k_interpolant, gsparams))
def __init__(self, real_kimage, imag_kimage, k_interpolant=None, stepk=None, gsparams=None): # make sure real_kimage, imag_kimage are really `Image`s, are floats, and are congruent. if not isinstance(real_kimage, galsim.Image) or not isinstance(imag_kimage, galsim.Image): raise ValueError("Supplied kimage is not an Image instance") if ((real_kimage.dtype != np.float32 and real_kimage.dtype != np.float64) or (imag_kimage.dtype != np.float32 and imag_kimage.dtype != np.float64)): raise ValueError("Supplied image does not have dtype of float32 or float64!") if real_kimage.bounds != imag_kimage.bounds: raise ValueError("Real and Imag kimages must have same bounds.") if real_kimage.scale != imag_kimage.scale: raise ValueError("Real and Imag kimages must have same scale.") # Make sure any `wcs`s are `PixelScale`s. if ((real_kimage.wcs is not None and not real_kimage.wcs.isPixelScale()) or (imag_kimage.wcs is not None and not imag_kimage.wcs.isPixelScale())): raise ValueError("Real and Imag kimage wcs's must be PixelScale's or None.") # Check for Hermitian symmetry properties of real_kimage and imag_kimage shape = real_kimage.array.shape # If image is even-sized, ignore first row/column since in this case not every pixel has # a symmetric partner to which to compare. bd = galsim.BoundsI(real_kimage.xmin + (1 if shape[1]%2==0 else 0), real_kimage.xmax, real_kimage.ymin + (1 if shape[0]%2==0 else 0), real_kimage.ymax) if not (np.allclose(real_kimage[bd].array, real_kimage[bd].array[::-1,::-1]) and np.allclose(imag_kimage[bd].array, -imag_kimage[bd].array[::-1,::-1])): raise ValueError("Real and Imag kimages must form a Hermitian complex matrix.") if stepk is None: stepk = real_kimage.scale else: if stepk < real_kimage.scale: import warnings warnings.warn( "Provided stepk is smaller than kimage.scale; overriding with kimage.scale.") stepk = real_kimage.scale self._real_kimage = real_kimage self._imag_kimage = imag_kimage self._stepk = stepk self._gsparams = gsparams # set up k_interpolant if none was provided by user, or check that the user-provided one # is of a valid type if k_interpolant is None: self.k_interpolant = galsim.Quintic(tol=1e-4) else: self.k_interpolant = galsim.utilities.convert_interpolant(k_interpolant) GSObject.__init__(self, galsim._galsim.SBInterpolatedKImage( self._real_kimage.image, self._imag_kimage.image, self._real_kimage.scale, self._stepk, self.k_interpolant, gsparams))
def setBVec(self,bvec): """This method is discouraged and will be deprecated.""" bvec_size = ShapeletSize(self.order) if len(bvec) != bvec_size: raise ValueError("bvec is the wrong size for the Shapelet order") import numpy bvec = LVector(self.order,numpy.array(bvec)) GSObject.__init__(self, galsim._galsim.SBShapelet(self.sigma, bvec))
def __init__(self, farg, gsparams=None): if isinstance(farg, GSObject): self.farg = farg GSObject.__init__( self, galsim.SBDeconvolve(self.farg.SBProfile, gsparams=gsparams)) else: raise TypeError("Argument to Deconvolve must be a GSObject.")
def __init__(self, lam_over_r0=None, fwhm=None, interpolant=None, oversampling=1.5, flux=1., gsparams=None): # The FWHM of the Kolmogorov PSF is ~0.976 lambda/r0 (e.g., Racine 1996, PASP 699, 108). if lam_over_r0 is None: if fwhm is not None: lam_over_r0 = fwhm / 0.976 else: raise TypeError( "Either lam_over_r0 or fwhm must be specified for AtmosphericPSF" ) else: if fwhm is None: fwhm = 0.976 * lam_over_r0 else: raise TypeError( "Only one of lam_over_r0 and fwhm may be specified for AtmosphericPSF" ) # Set the lookup table sample rate via FWHM / 2 / oversampling (BARNEY: is this enough??) dx_lookup = .5 * fwhm / oversampling # Fold at 10 times the FWHM stepk_kolmogorov = np.pi / (10. * fwhm) # Odd array to center the interpolant on the centroid. Might want to pad this later to # make a nice size array for FFT, but for typical seeing, arrays will be very small. npix = 1 + 2 * (np.ceil(np.pi / stepk_kolmogorov)).astype(int) atmoimage = kolmogorov_psf_image(array_shape=(npix, npix), dx=dx_lookup, lam_over_r0=lam_over_r0, flux=flux) # Run checks on the interpolant and build default if None if interpolant is None: quintic = galsim.Quintic(tol=1e-4) self.interpolant = galsim.InterpolantXY(quintic) else: self.interpolant = galsim.utilities.convert_interpolant_to_2d( interpolant) # Then initialize the SBProfile GSObject.__init__( self, galsim.SBInterpolatedImage(atmoimage, xInterp=self.interpolant, dx=dx_lookup, gsparams=gsparams)) # The above procedure ends up with a larger image than we really need, which # means that the default stepK value will be smaller than we need. # Thus, we call the function calculateStepK() to refine the value. self.SBProfile.calculateStepK() self.SBProfile.calculateMaxK()
def setBVec(self,bvec): sigma = self.SBProfile.getSigma() order = self.SBProfile.getBVec().order bvec_size = galsim.LVectorSize(order) if len(bvec) != bvec_size: raise ValueError("bvec is the wrong size for the Shapelet order") import numpy bvec = galsim.LVector(order,numpy.array(bvec)) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def setBVec(self, bvec): sigma = self.SBProfile.getSigma() order = self.SBProfile.getBVec().order bvec_size = galsim.LVectorSize(order) if len(bvec) != bvec_size: raise ValueError("bvec is the wrong size for the Shapelet order") import numpy bvec = galsim.LVector(order, numpy.array(bvec)) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def __init__(self, n, inclination, half_light_radius=None, scale_radius=None, scale_height=None, scale_h_over_r=None, flux=1., trunc=0., flux_untruncated=False, gsparams=None): # Check that the scale/half-light radius is valid if scale_radius is not None: if not scale_radius > 0.: raise ValueError("scale_radius must be > zero.") elif half_light_radius is not None: if not half_light_radius > 0.: raise ValueError("half_light_radius must be > zero.") else: raise TypeError( "Either scale_radius or half_light_radius must be " + "specified for InclinedSersic") # Check that we have exactly one of scale_radius and half_light_radius if half_light_radius is not None: if scale_radius is not None: raise TypeError( "Only one of scale_radius and half_light_radius may be " + "specified for InclinedSersic") # Check that the height specification is valid if scale_height is not None: if not scale_height > 0.: raise ValueError("scale_height must be > zero.") elif scale_h_over_r is not None: if not scale_h_over_r > 0.: raise ValueError("half_light_radius must be > zero.") else: # Use the default scale_h_over_r scale_h_over_r = 0.1 # Check that we have exactly one of scale_height and scale_h_over_r if scale_h_over_r is not None: if scale_height is not None: raise TypeError( "Only one of scale_height and scale_h_over_r may be " + "specified for InclinedExponential") # Check that trunc is valid if trunc < 0.: raise ValueError("trunc must be >= zero (zero implying no truncation).") # Explicitly check for angle type, so we can give more informative error if eg. a float is # passed if not isinstance(inclination, galsim.Angle): raise TypeError("Input inclination should be an Angle") GSObject.__init__(self, _galsim.SBInclinedSersic(n, inclination, scale_radius, half_light_radius, scale_height, scale_h_over_r, flux, trunc, flux_untruncated, gsparams)) self._flux_untruncated = flux_untruncated self._gsparams = gsparams
def setOrder(self,order): """This method is discouraged and will be deprecated.""" if self.order == order: return # Preserve the existing values as much as possible. if self.order > order: bvec = LVector(order, self.bvec[0:ShapeletSize(order)]) else: import numpy a = numpy.zeros(ShapeletSize(order)) a[0:len(self.bvec)] = self.bvec bvec = LVector(order,a) GSObject.__init__(self, galsim._galsim.SBShapelet(self.sigma, bvec))
def __init__(self, lam_over_diam, defocus=0., astig1=0., astig2=0., coma1=0., coma2=0., trefoil1=0., trefoil2=0., spher=0., circular_pupil=True, obscuration=0., interpolant=None, oversampling=1.5, pad_factor=1.5, suppress_warning=False, flux=1., nstruts=0, strut_thick=0.05, strut_angle=0.*galsim.degrees, gsparams=None): # Choose dx for lookup table using Nyquist for optical aperture and the specified # oversampling factor dx_lookup = .5 * lam_over_diam / oversampling # Start with the stepk value for Airy: airy = galsim.Airy(lam_over_diam = lam_over_diam, obscuration = obscuration, gsparams = gsparams) stepk_airy = airy.stepK() # Boost Airy image size by a user-specifed pad_factor to allow for larger, aberrated PSFs stepk = stepk_airy / pad_factor # Get a good FFT size. i.e. 2^n or 3 * 2^n. npix = goodFFTSize(int(np.ceil(2. * np.pi / (dx_lookup * stepk) ))) # Make the psf image using this dx and array shape optimage = galsim.optics.psf_image( lam_over_diam=lam_over_diam, dx=dx_lookup, array_shape=(npix, npix), defocus=defocus, astig1=astig1, astig2=astig2, coma1=coma1, coma2=coma2, trefoil1=trefoil1, trefoil2=trefoil2, spher=spher, circular_pupil=circular_pupil, obscuration=obscuration, flux=flux, nstruts=nstruts, strut_thick=strut_thick, strut_angle=strut_angle) # Initialize the SBProfile GSObject.__init__( self, galsim.InterpolatedImage(optimage, x_interpolant=interpolant, dx=dx_lookup, calculate_stepk=True, calculate_maxk=True, use_true_center=False, normalization='sb', gsparams=gsparams)) # The above procedure ends up with a larger image than we really need, which # means that the default stepK value will be smaller than we need. # Hence calculate_stepk=True and calculate_maxk=True above. if not suppress_warning: # Check the calculated stepk value. If it is smaller than stepk, then there might # be aliasing. final_stepk = self.SBProfile.stepK() if final_stepk < stepk: import warnings warnings.warn( "The calculated stepk (%g) for OpticalPSF is smaller "%final_stepk + "than what was used to build the wavefront (%g)."%stepk + "This could lead to aliasing problems. " + "Using pad_factor >= %f is recommended."%(pad_factor * stepk / final_stepk))
def __init__(self, lam_over_diam, defocus=0., astig1=0., astig2=0., coma1=0., coma2=0., trefoil1=0., trefoil2=0., spher=0., circular_pupil=True, obscuration=0., interpolant=None, oversampling=1.5, pad_factor=1.5, flux=1., gsparams=None): # Currently we load optics, noise etc in galsim/__init__.py, but this might change (???) import galsim.optics # Choose dx for lookup table using Nyquist for optical aperture and the specified # oversampling factor dx_lookup = .5 * lam_over_diam / oversampling # We need alias_threshold here, so don't wait to make this a default GSParams instance # if the user didn't specify anything else. if not gsparams: gsparams = galsim.GSParams() # Use a similar prescription as SBAiry to set Airy stepK and thus reference unpadded image # size in physical units stepk_airy = min( gsparams.alias_threshold * .5 * np.pi**3 * (1. - obscuration) / lam_over_diam, np.pi / 5. / lam_over_diam) # Boost Airy image size by a user-specifed pad_factor to allow for larger, aberrated PSFs, # also make npix always *odd* so that opticalPSF lookup table array is correctly centred: npix = 1 + 2 * (np.ceil(pad_factor * (np.pi / stepk_airy) / dx_lookup)).astype(int) # Make the psf image using this dx and array shape optimage = galsim.optics.psf_image( lam_over_diam=lam_over_diam, dx=dx_lookup, array_shape=(npix, npix), defocus=defocus, astig1=astig1, astig2=astig2, coma1=coma1, coma2=coma2, trefoil1=trefoil1, trefoil2=trefoil2, spher=spher, circular_pupil=circular_pupil, obscuration=obscuration, flux=flux) # If interpolant not specified on input, use a Quintic interpolant if interpolant is None: quintic = galsim.Quintic(tol=1e-4) self.interpolant = galsim.InterpolantXY(quintic) else: self.interpolant = galsim.utilities.convert_interpolant_to_2d(interpolant) # Initialize the SBProfile GSObject.__init__( self, galsim.SBInterpolatedImage(optimage, xInterp=self.interpolant, dx=dx_lookup, gsparams=gsparams)) # The above procedure ends up with a larger image than we really need, which # means that the default stepK value will be smaller than we need. # Thus, we call the function calculateStepK() to refine the value. self.SBProfile.calculateStepK() self.SBProfile.calculateMaxK()
def setOrder(self,order): curr_bvec = self.SBProfile.getBVec() curr_order = curr_bvec.order if curr_order == order: return # Preserve the existing values as much as possible. sigma = self.SBProfile.getSigma() if curr_order > order: bvec = galsim.LVector(order, curr_bvec.array[0:galsim.LVectorSize(order)]) else: import numpy a = numpy.zeros(galsim.LVectorSize(order)) a[0:len(curr_bvec.array)] = curr_bvec.array bvec = galsim.LVector(order,a) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def setOrder(self, order): curr_bvec = self.SBProfile.getBVec() curr_order = curr_bvec.order if curr_order == order: return # Preserve the existing values as much as possible. sigma = self.SBProfile.getSigma() if curr_order > order: bvec = galsim.LVector(order, curr_bvec.array[0:galsim.LVectorSize(order)]) else: import numpy a = numpy.zeros(galsim.LVectorSize(order)) a[0:len(curr_bvec.array)] = curr_bvec.array bvec = galsim.LVector(order, a) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def __init__(self, sigma, order, bvec=None, gsparams=None): # Make sure order and sigma are the right type: order = int(order) sigma = float(sigma) # Make bvec if necessary if bvec is None: bvec = LVector(order) else: bvec_size = ShapeletSize(order) if len(bvec) != bvec_size: raise ValueError("bvec is the wrong size for the provided order") import numpy bvec = LVector(order,numpy.array(bvec)) GSObject.__init__(self, galsim._galsim.SBShapelet(sigma, bvec, gsparams))
def fitImage(self, image, center=None, normalization='flux'): """Fit for a shapelet decomposition of a given image The optional normalization parameter mirrors the parameter in the GSObject `draw` method. If the fitted shapelet is drawn with the same normalization value as was used when it was fit, then the resulting image should be an approximate match to the original image. For example: image = ... shapelet = galsim.Shapelet(sigma, order) shapelet.fitImage(image,normalization='sb') shapelet.draw(image=image2, dx=image.scale, normalization='sb') Then image2 and image should be as close to the same as possible for the given sigma and order. Increasing the order can improve the fit, as can having sigma match the natural scale size of the image. However, it should be noted that some images are not well fit by a shapelet for any (reasonable) order. @param image The Image for which to fit the shapelet decomposition @param center The position in pixels to use for the center of the decomposition. [Default: use the image center (`image.bounds.trueCenter()`)] @param normalization The normalization to assume for the image. (Default `normalization = "flux"`) """ if not center: center = image.bounds.trueCenter() # convert from PositionI if necessary center = galsim.PositionD(center.x, center.y) if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(( "Invalid normalization requested: '%s'. Expecting one of 'flux', " + "'f', 'surface brightness' or 'sb'.") % normalization) sigma = self.SBProfile.getSigma() bvec = self.SBProfile.getBVec().copy() galsim.ShapeletFitImage(sigma, bvec, image, center) if normalization.lower() == "flux" or normalization.lower() == "f": bvec /= image.scale**2 # SBShapelet, like all SBProfiles, is immutable, so we need to reinitialize with a # new Shapelet object. GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def fitImage(self, image, center=None, normalization='flux'): """Fit for a shapelet decomposition of a given image The optional normalization parameter mirrors the parameter in the GSObject `draw` method. If the fitted shapelet is drawn with the same normalization value as was used when it was fit, then the resulting image should be an approximate match to the original image. For example: image = ... shapelet = galsim.Shapelet(sigma, order) shapelet.fitImage(image,normalization='sb') shapelet.draw(image=image2, dx=image.scale, normalization='sb') Then image2 and image should be as close to the same as possible for the given sigma and order. Increasing the order can improve the fit, as can having sigma match the natural scale size of the image. However, it should be noted that some images are not well fit by a shapelet for any (reasonable) order. @param image The Image for which to fit the shapelet decomposition @param center The position in pixels to use for the center of the decomposition. [Default: use the image center (`image.bounds.trueCenter()`)] @param normalization The normalization to assume for the image. (Default `normalization = "flux"`) """ if not center: center = image.bounds.trueCenter() # convert from PositionI if necessary center = galsim.PositionD(center.x,center.y) if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+ "'f', 'surface brightness' or 'sb'.") % normalization) sigma = self.SBProfile.getSigma() bvec = self.SBProfile.getBVec().copy() galsim.ShapeletFitImage(sigma, bvec, image, center) if normalization.lower() == "flux" or normalization.lower() == "f": bvec /= image.scale**2 # SBShapelet, like all SBProfiles, is immutable, so we need to reinitialize with a # new Shapelet object. GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def __init__(self, lam_over_r0=None, fwhm=None, interpolant=None, oversampling=1.5, flux=1., gsparams=None): # The FWHM of the Kolmogorov PSF is ~0.976 lambda/r0 (e.g., Racine 1996, PASP 699, 108). if lam_over_r0 is None : if fwhm is not None : lam_over_r0 = fwhm / 0.976 else: raise TypeError("Either lam_over_r0 or fwhm must be specified for AtmosphericPSF") else : if fwhm is None: fwhm = 0.976 * lam_over_r0 else: raise TypeError( "Only one of lam_over_r0 and fwhm may be specified for AtmosphericPSF") # Set the lookup table sample rate via FWHM / 2 / oversampling (BARNEY: is this enough??) dx_lookup = .5 * fwhm / oversampling # Fold at 10 times the FWHM stepk_kolmogorov = np.pi / (10. * fwhm) # Odd array to center the interpolant on the centroid. Might want to pad this later to # make a nice size array for FFT, but for typical seeing, arrays will be very small. npix = 1 + 2 * (np.ceil(np.pi / stepk_kolmogorov)).astype(int) atmoimage = kolmogorov_psf_image( array_shape=(npix, npix), dx=dx_lookup, lam_over_r0=lam_over_r0, flux=flux) # Run checks on the interpolant and build default if None if interpolant is None: quintic = galsim.Quintic(tol=1e-4) self.interpolant = galsim.InterpolantXY(quintic) else: self.interpolant = galsim.utilities.convert_interpolant_to_2d(interpolant) # Then initialize the SBProfile GSObject.__init__( self, galsim.SBInterpolatedImage(atmoimage, xInterp=self.interpolant, dx=dx_lookup, gsparams=gsparams)) # The above procedure ends up with a larger image than we really need, which # means that the default stepK value will be smaller than we need. # Thus, we call the function calculateStepK() to refine the value. self.SBProfile.calculateStepK() self.SBProfile.calculateMaxK()
def __init__(self, *args, **kwargs): # Check kwargs first: gsparams = kwargs.pop("gsparams", None) # Make sure there is nothing left in the dict. if kwargs: raise TypeError( "Add constructor got unexpected keyword argument(s): %s"%kwargs.keys()) if len(args) == 0: # No arguments. Could initialize with an empty list but draw then segfaults. Raise an # exception instead. raise ValueError("Add must be initialized with at least one GSObject.") elif len(args) == 1: # 1 argument. Should be either a GSObject or a list of GSObjects if isinstance(args[0], GSObject): args = [args[0]] elif isinstance(args[0], list): args = args[0] else: raise TypeError("Single input argument must be a GSObject or list of them.") # else args is already the list of objects if len(args) == 1: # No need to make an SBAdd in this case. GSObject.__init__(self, args[0]) if hasattr(args[0],'noise'): self.noise = args[0].noise else: # If any of the objects have a noise attribute, then we propagate the sum of the # noises (they add like variances) to the final sum. noise = None for obj in args: if hasattr(obj,'noise'): if noise is None: noise = obj.noise else: noise += obj.noise SBList = [obj.SBProfile for obj in args] GSObject.__init__(self, galsim.SBAdd(SBList, gsparams=gsparams)) if noise is not None: self.noise = noise
def __init__(self, lam_over_diam, defocus=0., astig1=0., astig2=0., coma1=0., coma2=0., trefoil1=0., trefoil2=0., spher=0., circular_pupil=True, obscuration=0., interpolant=None, oversampling=1.5, pad_factor=1.5, flux=1., nstruts=0, strut_thick=0.05, strut_angle=0.*galsim.degrees, gsparams=None): # Currently we load optics, noise etc in galsim/__init__.py, but this might change (???) import galsim.optics # Choose dx for lookup table using Nyquist for optical aperture and the specified # oversampling factor dx_lookup = .5 * lam_over_diam / oversampling # We need alias_threshold here, so don't wait to make this a default GSParams instance # if the user didn't specify anything else. if not gsparams: gsparams = galsim.GSParams() # Use a similar prescription as SBAiry to set Airy stepK and thus reference unpadded image # size in physical units stepk_airy = min( gsparams.alias_threshold * .5 * np.pi**3 * (1. - obscuration) / lam_over_diam, np.pi / 5. / lam_over_diam) # Boost Airy image size by a user-specifed pad_factor to allow for larger, aberrated PSFs, # also make npix always *odd* so that opticalPSF lookup table array is correctly centred: npix = 1 + 2 * (np.ceil(pad_factor * (np.pi / stepk_airy) / dx_lookup)).astype(int) # Make the psf image using this dx and array shape optimage = galsim.optics.psf_image( lam_over_diam=lam_over_diam, dx=dx_lookup, array_shape=(npix, npix), defocus=defocus, astig1=astig1, astig2=astig2, coma1=coma1, coma2=coma2, trefoil1=trefoil1, trefoil2=trefoil2, spher=spher, circular_pupil=circular_pupil, obscuration=obscuration, flux=flux, nstruts=nstruts, strut_thick=strut_thick, strut_angle=strut_angle) # Initialize the SBProfile GSObject.__init__( self, galsim.InterpolatedImage(optimage, x_interpolant=interpolant, dx=dx_lookup, calculate_stepk=True, calculate_maxk=True, use_true_center=False, normalization='sb', gsparams=gsparams))
def __init__(self, inclination, scale_radius, scale_height=None, scale_h_over_r=0.1, flux=1., gsparams=None): if scale_height is None: scale_height = scale_h_over_r * scale_radius # Explicitly check for angle type, so we can give more informative error if eg. a float is # passed if not isinstance(inclination, galsim.Angle): raise TypeError("Input inclination should be an Angle") GSObject.__init__( self, _galsim.SBInclinedExponential(inclination, scale_radius, scale_height, flux, gsparams)) self._gsparams = gsparams
def __init__(self, image, x_interpolant = None, k_interpolant = None, normalization = 'flux', dx = None, flux = None, pad_factor = 0., noise_pad = 0., rng = None, pad_image = None, calculate_stepk=True, calculate_maxk=True, use_cache=True, use_true_center=True, gsparams=None): import numpy as np # first try to read the image as a file. If it's not either a string or a valid # pyfits hdu or hdulist, then an exception will be raised, which we ignore and move on. try: image = galsim.fits.read(image) except: pass # make sure image is really an image and has a float type if not isinstance(image, galsim.BaseImageF) and not isinstance(image, galsim.BaseImageD): raise ValueError("Supplied image is not an image of floats or doubles!") # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor if not image.getBounds().isDefined(): raise ValueError("Supplied image does not have bounds defined!") # check what normalization was specified for the image: is it an image of surface # brightness, or flux? if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+ "'f', 'surface brightness', or 'sb'.") % normalization) # set up the interpolants if none was provided by user, or check that the user-provided ones # are of a valid type if x_interpolant is None: self.x_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) else: self.x_interpolant = galsim.utilities.convert_interpolant_to_2d(x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) else: self.k_interpolant = galsim.utilities.convert_interpolant_to_2d(k_interpolant) # Check for input dx, and check whether Image already has one set. At the end of this # code block, either an exception will have been raised, or the input image will have a # valid scale set. if dx is None: dx = image.scale if dx == 0: raise ValueError("No information given with Image or keywords about pixel scale!") else: if type(dx) != float: dx = float(dx) # Don't change the original image. Make a new view if we need to set the scale. image = image.view() image.setScale(dx) if dx == 0.0: raise ValueError("dx may not be 0.0") # Set up the GaussianDeviate if not provided one, or check that the user-provided one is # of a valid type. if rng is None: gaussian_deviate = galsim.GaussianDeviate() elif isinstance(rng, galsim.BaseDeviate): # Even if it's already a GaussianDeviate, we still want to make a new Gaussian deviate # that would generate the same sequence, because later we change the sigma and we don't # want to change it for the original one that was passed in. So don't distinguish # between GaussianDeviate and the other BaseDeviates here. gaussian_deviate = galsim.GaussianDeviate(rng) else: raise TypeError("rng provided to InterpolatedImage constructor is not a BaseDeviate") # decide about deterministic image padding specify_size = False padded_size = image.getPaddedSize(pad_factor) if pad_image: specify_size = True if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if ( not isinstance(pad_image, galsim.BaseImageF) and not isinstance(pad_image, galsim.BaseImageD) ): raise ValueError("Supplied pad_image is not one of the allowed types!") # If an image was supplied directly or from a file, check its size: # Cannot use if too small. # Use to define the final image size otherwise. deltax = (1+pad_image.getXMax()-pad_image.getXMin())-(1+image.getXMax()-image.getXMin()) deltay = (1+pad_image.getYMax()-pad_image.getYMin())-(1+image.getYMax()-image.getYMin()) if deltax < 0 or deltay < 0: raise RuntimeError("Image supplied for padding is too small!") if pad_factor != 1. and pad_factor != 0.: import warnings msg = "Warning: ignoring specified pad_factor because user also specified\n" msg += " an image to use directly for the padding." warnings.warn(msg) elif noise_pad: if isinstance(image, galsim.BaseImageF): pad_image = galsim.ImageF(padded_size, padded_size) if isinstance(image, galsim.BaseImageD): pad_image = galsim.ImageD(padded_size, padded_size) # now decide about noise padding # First, see if the input is consistent with a float. # i.e. it could be an int, or a str that converts to a number. try: noise_pad = float(noise_pad) except: pass if isinstance(noise_pad, float): if noise_pad < 0.: raise ValueError("Noise variance cannot be negative!") elif noise_pad > 0.: # Note: make sure the sigma is properly set to sqrt(noise_pad). gaussian_deviate.setSigma(np.sqrt(noise_pad)) pad_image.addNoise(galsim.DeviateNoise(gaussian_deviate)) else: if isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise): cn = noise_pad.copy() if rng: # Let a user supplied RNG take precedence over that in user CN cn.setRNG(gaussian_deviate) elif isinstance(noise_pad,galsim.BaseImageF) or isinstance(noise_pad,galsim.BaseImageD): cn = galsim.CorrelatedNoise(gaussian_deviate, noise_pad) elif use_cache and noise_pad in InterpolatedImage._cache_noise_pad: cn = InterpolatedImage._cache_noise_pad[noise_pad] if rng: # Make sure that we are using a specified RNG by resetting that in this cached # CorrelatedNoise instance, otherwise preserve the cached RNG cn.setRNG(gaussian_deviate) elif isinstance(noise_pad, str): cn = galsim.CorrelatedNoise(gaussian_deviate, galsim.fits.read(noise_pad)) if use_cache: InterpolatedImage._cache_noise_pad[noise_pad] = cn else: raise ValueError( "Input noise_pad must be a float/int, a CorrelatedNoise, Image, or filename "+ "containing an image to use to make a CorrelatedNoise!") pad_image.addNoise(cn) # Now we have to check: was the padding determined using pad_factor? Or by passing in an # image for padding? Treat these cases differently: # (1) If the former, then we can simply have the C++ handle the padding process. # (2) If the latter, then we have to do the padding ourselves, and pass the resulting image # to the C++ with pad_factor explicitly set to 1. if specify_size is False: # Make the SBInterpolatedImage out of the image. sbinterpolatedimage = galsim.SBInterpolatedImage( image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=dx, pad_factor=pad_factor, pad_image=pad_image, gsparams=gsparams) self.x_size = padded_size self.y_size = padded_size else: # Leave the original image as-is. Instead, we shift around the image to be used for # padding. Find out how much x and y margin there should be on lower end: x_marg = int(np.round(0.5*deltax)) y_marg = int(np.round(0.5*deltay)) # Now reset the pad_image to contain the original image in an even way pad_image = pad_image.view() pad_image.setScale(dx) pad_image.setOrigin(image.getXMin()-x_marg, image.getYMin()-y_marg) # Set the central values of pad_image to be equal to the input image pad_image[image.bounds] = image sbinterpolatedimage = galsim.SBInterpolatedImage( pad_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=dx, pad_factor=1., gsparams=gsparams) self.x_size = 1+pad_image.getXMax()-pad_image.getXMin() self.y_size = 1+pad_image.getYMax()-pad_image.getYMin() # GalSim cannot automatically know what stepK and maxK are appropriate for the # input image. So it is usually worth it to do a manual calculation here. if calculate_stepk: sbinterpolatedimage.calculateStepK() if calculate_maxk: sbinterpolatedimage.calculateMaxK() # If the user specified a flux, then set to that flux value. if flux != None: if type(flux) != flux: flux = float(flux) sbinterpolatedimage.setFlux(flux) # If the user specified a flux normalization for the input Image, then since # SBInterpolatedImage works in terms of surface brightness, have to rescale the values to # get proper normalization. elif flux is None and normalization.lower() in ['flux','f'] and dx != 1.: sbinterpolatedimage.scaleFlux(1./(dx**2)) # If the input Image normalization is 'sb' then since that is the SBInterpolated default # assumption, no rescaling is needed. # Initialize the SBProfile GSObject.__init__(self, sbinterpolatedimage) # Fix the center to be in the right place. # Note the minus sign in front of image.scale, since we want to fix the center in the # opposite sense of what the draw function does. if use_true_center: prof = self._fix_center(image, -image.scale) GSObject.__init__(self, prof.SBProfile)
def __init__(self, kimage=None, k_interpolant=None, stepk=None, gsparams=None, real_kimage=None, imag_kimage=None, real_hdu=None, imag_hdu=None): if isinstance(kimage, galsim.Image) and isinstance( k_interpolant, galsim.Image): from .deprecated import depr depr( 'InterpolatedKImage(re,im,...)', 1.5, 'either InterpolatedKImage(re + 1j * im, ...) or ' 'InterpolatedKImage(real_kimage=re, imag_kimage=im)') # This won't work if they call InterpolatedKImage(re,im, k_interpolant=kinterp) # But I don't see an easy way around that, so I guess that use case is not # backwards compatible. Sorry.. real_kimage = kimage imag_kimage = k_interpolant kimage = None k_interpolant = None if kimage is None: if real_kimage is None or imag_kimage is None: raise ValueError( "Must provide either kimage or real_kimage/imag_kimage") # If the "image" is not actually an image, try to read the image as a file. if not isinstance(real_kimage, galsim.Image): real_kimage = galsim.fits.read(real_kimage, hdu=real_hdu) if not isinstance(imag_kimage, galsim.Image): imag_kimage = galsim.fits.read(imag_kimage, hdu=imag_hdu) # make sure real_kimage, imag_kimage are really `Image`s, are floats, and are # congruent. if not isinstance(real_kimage, galsim.Image): raise ValueError( "Supplied real_kimage is not an Image instance") if not isinstance(imag_kimage, galsim.Image): raise ValueError( "Supplied imag_kimage is not an Image instance") if real_kimage.bounds != imag_kimage.bounds: raise ValueError( "Real and Imag kimages must have same bounds.") if real_kimage.wcs != imag_kimage.wcs: raise ValueError( "Real and Imag kimages must have same scale/wcs.") kimage = real_kimage + 1j * imag_kimage else: if real_kimage is not None or imag_kimage is not None: raise ValueError( "Cannot provide both kimage and real_kimage/imag_kimage") if not kimage.iscomplex: raise ValueError("Supplied kimage is not an ImageC") # Make sure wcs is a PixelScale. if kimage.wcs is not None and not kimage.wcs.isPixelScale(): raise ValueError("kimage wcs must be PixelScale or None.") # Check for Hermitian symmetry properties of kimage shape = kimage.array.shape # If image is even-sized, ignore first row/column since in this case not every pixel has # a symmetric partner to which to compare. bd = galsim.BoundsI(kimage.xmin + (1 if shape[1] % 2 == 0 else 0), kimage.xmax, kimage.ymin + (1 if shape[0] % 2 == 0 else 0), kimage.ymax) if not (np.allclose(kimage[bd].real.array, kimage[bd].real.array[::-1, ::-1]) and np.allclose(kimage[bd].imag.array, -kimage[bd].imag.array[::-1, ::-1])): raise ValueError( "Real and Imag kimages must form a Hermitian complex matrix.") if stepk is None: stepk = kimage.scale else: if stepk < kimage.scale: import warnings warnings.warn( "Provided stepk is smaller than kimage.scale; overriding with kimage.scale." ) stepk = kimage.scale self._kimage = kimage self._stepk = stepk self._gsparams = gsparams # set up k_interpolant if none was provided by user, or check that the user-provided one # is of a valid type if k_interpolant is None: self.k_interpolant = galsim.Quintic(tol=1e-4) else: self.k_interpolant = galsim.utilities.convert_interpolant( k_interpolant) GSObject.__init__( self, galsim._galsim.SBInterpolatedKImage(self._kimage.image, self._kimage.scale, self._stepk, self.k_interpolant, gsparams))
def applyDilation(self, scale): sigma = self.SBProfile.getSigma() * scale bvec = self.SBProfile.getBVec() GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def setPQ(self, p, q, re, im=0.): sigma = self.SBProfile.getSigma() bvec = self.SBProfile.getBVec().copy() bvec.setPQ(p, q, re, im) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def applyMagnification(self, mu): import numpy sigma = self.SBProfile.getSigma() * numpy.sqrt(mu) bvec = self.SBProfile.getBVec() * mu GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def __init__(self, lam_over_diam, defocus=0., astig1=0., astig2=0., coma1=0., coma2=0., trefoil1=0., trefoil2=0., spher=0., circular_pupil=True, obscuration=0., interpolant=None, oversampling=1.5, pad_factor=1.5, flux=1., gsparams=None): # Currently we load optics, noise etc in galsim/__init__.py, but this might change (???) import galsim.optics # Choose dx for lookup table using Nyquist for optical aperture and the specified # oversampling factor dx_lookup = .5 * lam_over_diam / oversampling # We need alias_threshold here, so don't wait to make this a default GSParams instance # if the user didn't specify anything else. if not gsparams: gsparams = galsim.GSParams() # Use a similar prescription as SBAiry to set Airy stepK and thus reference unpadded image # size in physical units stepk_airy = min( gsparams.alias_threshold * .5 * np.pi**3 * (1. - obscuration) / lam_over_diam, np.pi / 5. / lam_over_diam) # Boost Airy image size by a user-specifed pad_factor to allow for larger, aberrated PSFs, # also make npix always *odd* so that opticalPSF lookup table array is correctly centred: npix = 1 + 2 * (np.ceil(pad_factor * (np.pi / stepk_airy) / dx_lookup)).astype(int) # Make the psf image using this dx and array shape optimage = galsim.optics.psf_image(lam_over_diam=lam_over_diam, dx=dx_lookup, array_shape=(npix, npix), defocus=defocus, astig1=astig1, astig2=astig2, coma1=coma1, coma2=coma2, trefoil1=trefoil1, trefoil2=trefoil2, spher=spher, circular_pupil=circular_pupil, obscuration=obscuration, flux=flux) # If interpolant not specified on input, use a Quintic interpolant if interpolant is None: quintic = galsim.Quintic(tol=1e-4) self.interpolant = galsim.InterpolantXY(quintic) else: self.interpolant = galsim.utilities.convert_interpolant_to_2d( interpolant) # Initialize the SBProfile GSObject.__init__( self, galsim.SBInterpolatedImage(optimage, xInterp=self.interpolant, dx=dx_lookup, gsparams=gsparams)) # The above procedure ends up with a larger image than we really need, which # means that the default stepK value will be smaller than we need. # Thus, we call the function calculateStepK() to refine the value. self.SBProfile.calculateStepK() self.SBProfile.calculateMaxK()
def __init__(self, real_galaxy_catalog, index=None, id=None, random=False, rng=None, x_interpolant=None, k_interpolant=None, flux=None, flux_rescale=None, pad_factor=4, noise_pad_size=0, gsparams=None, logger=None): if rng is None: self.rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("The rng provided to RealGalaxy constructor is not a BaseDeviate") else: self.rng = rng self._rng = self.rng.duplicate() # This is only needed if we want to make sure eval(repr) # results in the same object. if flux is not None and flux_rescale is not None: raise TypeError("Cannot supply a flux and a flux rescaling factor!") if isinstance(real_galaxy_catalog, tuple): # Special (undocumented) way to build a RealGalaxy without needing the rgc directly # by providing the things we need from it. Used by COSMOSGalaxy. self.gal_image, self.psf_image, noise_image, pixel_scale, var = real_galaxy_catalog use_index = 0 # For the logger statements below. if logger: logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index) self.catalog_file = None else: # Get the index to use in the catalog if index is not None: if id is not None or random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = index elif id is not None: if random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = real_galaxy_catalog.getIndexForID(id) elif random is True: uniform_deviate = galsim.UniformDeviate(self.rng) use_index = int(real_galaxy_catalog.nobjects * uniform_deviate()) else: raise AttributeError('No method specified for selecting a galaxy!') if logger: logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index) # Read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. self.gal_image = real_galaxy_catalog.getGal(use_index) if logger: logger.debug('RealGalaxy %d: Got gal_image',use_index) self.psf_image = real_galaxy_catalog.getPSF(use_index) if logger: logger.debug('RealGalaxy %d: Got psf_image',use_index) #self.noise = real_galaxy_catalog.getNoise(use_index, self.rng, gsparams) # We need to duplication some of the RealGalaxyCatalog.getNoise() function, since we # want it to be possible to have the RealGalaxyCatalog in another process, and the # BaseCorrelatedNoise object is not picklable. So we just build it here instead. noise_image, pixel_scale, var = real_galaxy_catalog.getNoiseProperties(use_index) if logger: logger.debug('RealGalaxy %d: Got noise_image',use_index) self.catalog_file = real_galaxy_catalog.getFileName() if noise_image is None: self.noise = galsim.UncorrelatedNoise(var, rng=self.rng, scale=pixel_scale, gsparams=gsparams) else: ii = galsim.InterpolatedImage(noise_image, normalization="sb", calculate_stepk=False, calculate_maxk=False, x_interpolant='linear', gsparams=gsparams) self.noise = galsim.correlatednoise._BaseCorrelatedNoise(self.rng, ii, noise_image.wcs) self.noise = self.noise.withVariance(var) if logger: logger.debug('RealGalaxy %d: Finished building noise',use_index) # Save any other relevant information as instance attributes self.catalog = real_galaxy_catalog self.index = use_index self.pixel_scale = float(pixel_scale) self._x_interpolant = x_interpolant self._k_interpolant = k_interpolant self._pad_factor = pad_factor self._noise_pad_size = noise_pad_size self._flux = flux self._gsparams = gsparams # Convert noise_pad to the right noise to pass to InterpolatedImage if noise_pad_size: noise_pad = self.noise else: noise_pad = 0. # Build the InterpolatedImage of the PSF. self.original_psf = galsim.InterpolatedImage( self.psf_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, flux=1.0, gsparams=gsparams) if logger: logger.debug('RealGalaxy %d: Made original_psf',use_index) # Build the InterpolatedImage of the galaxy. # Use the stepK() value of the PSF as a maximum value for stepK of the galaxy. # (Otherwise, low surface brightness galaxies can get a spuriously high stepk, which # leads to problems.) self.original_gal = galsim.InterpolatedImage( self.gal_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, pad_factor=pad_factor, noise_pad_size=noise_pad_size, calculate_stepk=self.original_psf.stepK(), calculate_maxk=self.original_psf.maxK(), noise_pad=noise_pad, rng=self.rng, gsparams=gsparams) if logger: logger.debug('RealGalaxy %d: Made original_gal',use_index) # If flux is None, leave flux as given by original image if flux is not None: flux_rescale = flux / self.original_gal.getFlux() if flux_rescale is not None: self.original_gal *= flux_rescale self.noise *= flux_rescale**2 # Calculate the PSF "deconvolution" kernel psf_inv = galsim.Deconvolve(self.original_psf, gsparams=gsparams) # Initialize the SBProfile attribute GSObject.__init__( self, galsim.Convolve([self.original_gal, psf_inv], gsparams=gsparams)) if logger: logger.debug('RealGalaxy %d: Made gsobject',use_index) # Save the noise in the image as an accessible attribute self.noise = self.noise.convolvedWith(psf_inv, gsparams) if logger: logger.debug('RealGalaxy %d: Finished building RealGalaxy',use_index)
def __init__(self, image, x_interpolant=None, k_interpolant=None, normalization='flux', scale=None, wcs=None, flux=None, pad_factor=4., noise_pad_size=0, noise_pad=0., rng=None, pad_image=None, calculate_stepk=True, calculate_maxk=True, use_cache=True, use_true_center=True, offset=None, gsparams=None, dx=None, _force_stepk=0., _force_maxk=0., _serialize_stepk=None, _serialize_maxk=None, hdu=None): # Check for obsolete dx parameter if dx is not None and scale is None: from galsim.deprecated import depr depr('dx', 1.1, 'scale') scale = dx # If the "image" is not actually an image, try to read the image as a file. if not isinstance(image, galsim.Image): image = galsim.fits.read(image, hdu=hdu) # make sure image is really an image and has a float type if image.dtype != np.float32 and image.dtype != np.float64: raise ValueError( "Supplied image does not have dtype of float32 or float64!") # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor if not image.bounds.isDefined(): raise ValueError("Supplied image does not have bounds defined!") # check what normalization was specified for the image: is it an image of surface # brightness, or flux? if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(( "Invalid normalization requested: '%s'. Expecting one of 'flux', " + "'f', 'surface brightness', or 'sb'.") % normalization) # set up the interpolants if none was provided by user, or check that the user-provided ones # are of a valid type if x_interpolant is None: self.x_interpolant = galsim.Quintic(tol=1e-4) else: self.x_interpolant = galsim.utilities.convert_interpolant( x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.Quintic(tol=1e-4) else: self.k_interpolant = galsim.utilities.convert_interpolant( k_interpolant) # Store the image as an attribute and make sure we don't change the original image # in anything we do here. (e.g. set scale, etc.) self.image = image.view() self.use_cache = use_cache # Set the wcs if necessary if scale is not None: if wcs is not None: raise TypeError( "Cannot provide both scale and wcs to InterpolatedImage") self.image.wcs = galsim.PixelScale(scale) elif wcs is not None: if not isinstance(wcs, galsim.BaseWCS): raise TypeError( "wcs parameter is not a galsim.BaseWCS instance") self.image.wcs = wcs elif self.image.wcs is None: raise ValueError( "No information given with Image or keywords about pixel scale!" ) # Set up the GaussianDeviate if not provided one, or check that the user-provided one is # of a valid type. if rng is None: if noise_pad: rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError( "rng provided to InterpolatedImage constructor is not a BaseDeviate" ) # Check that given pad_image is valid: if pad_image: if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if not isinstance(pad_image, galsim.Image): raise ValueError("Supplied pad_image is not an Image!") if pad_image.dtype != np.float32 and pad_image.dtype != np.float64: raise ValueError( "Supplied pad_image is not one of the allowed types!") # Check that the given noise_pad is valid: try: noise_pad = float(noise_pad) except: pass if isinstance(noise_pad, float): if noise_pad < 0.: raise ValueError("Noise variance cannot be negative!") # There are other options for noise_pad, the validity of which will be checked in # the helper function self.buildNoisePadImage() # This will be passed to SBInterpolatedImage, so make sure it is the right type. pad_factor = float(pad_factor) if pad_factor <= 0.: raise ValueError("Invalid pad_factor <= 0 in InterpolatedImage") if use_true_center: im_cen = self.image.bounds.trueCenter() else: im_cen = self.image.bounds.center() local_wcs = self.image.wcs.local(image_pos=im_cen) self.min_scale = local_wcs.minLinearScale() self.max_scale = local_wcs.maxLinearScale() # Make sure the image fits in the noise pad image: if noise_pad_size: import math # Convert from arcsec to pixels according to the local wcs. # Use the minimum scale, since we want to make sure noise_pad_size is # as large as we need in any direction. noise_pad_size = int(math.ceil(noise_pad_size / self.min_scale)) # Round up to a good size for doing FFTs noise_pad_size = galsim._galsim.goodFFTSize(noise_pad_size) if noise_pad_size <= min(self.image.array.shape): # Don't need any noise padding in this case. noise_pad_size = 0 elif noise_pad_size < max(self.image.array.shape): noise_pad_size = max(self.image.array.shape) # See if we need to pad out the image with either a pad_image or noise_pad if noise_pad_size: new_pad_image = self.buildNoisePadImage(noise_pad_size, noise_pad, rng) if pad_image: # if both noise_pad and pad_image are set, then we need to build up a larger # pad_image and place the given pad_image in the center. # We will change the bounds here, so make a new view to avoid modifying the # input pad_image. pad_image = pad_image.view() pad_image.setCenter(0, 0) new_pad_image.setCenter(0, 0) if new_pad_image.bounds.includes(pad_image.bounds): new_pad_image[pad_image.bounds] = pad_image else: new_pad_image = pad_image pad_image = new_pad_image elif pad_image: # Just make sure pad_image is the right type pad_image = galsim.Image(pad_image, dtype=image.dtype) # Now place the given image in the center of the padding image: if pad_image: pad_image.setCenter(0, 0) self.image.setCenter(0, 0) if pad_image.bounds.includes(self.image.bounds): pad_image[self.image.bounds] = self.image pad_image.wcs = self.image.wcs else: # If padding was smaller than original image, just use the original image. pad_image = self.image else: pad_image = self.image # GalSim cannot automatically know what stepK and maxK are appropriate for the # input image. So it is usually worth it to do a manual calculation (below). # # However, there is also a hidden option to force it to use specific values of stepK and # maxK (caveat user!). The values of _force_stepk and _force_maxk should be provided in # terms of physical scale, e.g., for images that have a scale length of 0.1 arcsec, the # stepK and maxK should be provided in units of 1/arcsec. Then we convert to the 1/pixel # units required by the C++ layer below. Also note that profile recentering for even-sized # images (see the ._fix_center step below) leads to automatic reduction of stepK slightly # below what is provided here, while maxK is preserved. if _force_stepk > 0.: calculate_stepk = False _force_stepk *= self.min_scale if _force_maxk > 0.: calculate_maxk = False _force_maxk *= self.max_scale # Due to floating point rounding errors, for pickling it's necessary to store the exact # _force_maxk and _force_stepk used to create the SBInterpolatedImage, as opposed to the # values before being scaled by self.min_scale and self.max_scale. So we do that via the # _serialize_maxk and _serialize_stepk hidden kwargs, which should only get used during # pickling. if _serialize_stepk is not None: calculate_stepk = False _force_stepk = _serialize_stepk if _serialize_maxk is not None: calculate_maxk = False _force_maxk = _serialize_maxk # Save these values for pickling self._pad_image = pad_image self._pad_factor = pad_factor self._gsparams = gsparams # Make the SBInterpolatedImage out of the image. sbii = galsim._galsim.SBInterpolatedImage(pad_image.image, self.x_interpolant, self.k_interpolant, pad_factor, _force_stepk, _force_maxk, gsparams) # I think the only things that will mess up if getFlux() == 0 are the # calculateStepK and calculateMaxK functions, and rescaling the flux to some value. if (calculate_stepk or calculate_maxk or flux is not None) and sbii.getFlux() == 0.: raise RuntimeError( "This input image has zero total flux. " "It does not define a valid surface brightness profile.") if calculate_stepk: if calculate_stepk is True: sbii.calculateStepK() else: # If not a bool, then value is max_stepk sbii.calculateStepK(max_stepk=calculate_stepk) if calculate_maxk: if calculate_maxk is True: sbii.calculateMaxK() else: # If not a bool, then value is max_maxk sbii.calculateMaxK(max_maxk=calculate_maxk) # If the user specified a surface brightness normalization for the input Image, then # need to rescale flux by the pixel area to get proper normalization. if flux is None and normalization.lower() in [ 'surface brightness', 'sb' ]: flux = sbii.getFlux() * local_wcs.pixelArea() # Save this intermediate profile self._sbii = sbii self._stepk = sbii.stepK() / self.min_scale self._maxk = sbii.maxK() / self.max_scale self._flux = flux self._serialize_stepk = sbii.stepK() self._serialize_maxk = sbii.maxK() prof = GSObject(sbii) # Make sure offset is a PositionD offset = prof._parse_offset(offset) # Apply the offset, and possibly fix the centering for even-sized images # Note reverse=True, since we want to fix the center in the opposite sense of what the # draw function does. prof = prof._fix_center(self.image.array.shape, offset, use_true_center, reverse=True) # Save the offset we will need when pickling. if hasattr(prof, 'offset'): self._offset = -prof.offset else: self._offset = None # Bring the profile from image coordinates into world coordinates prof = local_wcs.toWorld(prof) # If the user specified a flux, then set to that flux value. if flux is not None: prof = prof.withFlux(float(flux)) # Now, in order for these to pickle correctly if they are the "original" object in a # Transform object, we need to hide the current transformation. An easy way to do that # is to hide the SBProfile in an SBAdd object. sbp = galsim._galsim.SBAdd([prof.SBProfile]) GSObject.__init__(self, sbp)
def __init__(self, *args, **kwargs): # First check for number of arguments != 0 if len(args) == 0: # No arguments. Could initialize with an empty list but draw then segfaults. Raise an # exception instead. raise ValueError("Convolve must be initialized with at least one GSObject.") elif len(args) == 1: if isinstance(args[0], GSObject): args = [args[0]] elif isinstance(args[0], list): args = args[0] else: raise TypeError("Single input argument must be a GSObject or list of them.") # else args is already the list of objects if len(args) == 1: # No need to make an SBConvolve in this case. Can early exit. GSObject.__init__(self, args[0]) if hasattr(args[0],'noise'): self.noise = args[0].noise return # Check kwargs # real_space can be True or False (default if omitted is None), which specifies whether to # do the convolution as an integral in real space rather than as a product in fourier # space. If the parameter is omitted (or explicitly given as None I guess), then # we will usually do the fourier method. However, if there are 2 components _and_ both of # them have hard edges, then we use real-space convolution. real_space = kwargs.pop("real_space", None) gsparams = kwargs.pop("gsparams", None) # Make sure there is nothing left in the dict. if kwargs: raise TypeError( "Convolve constructor got unexpected keyword argument(s): %s"%kwargs.keys()) # Check whether to perform real space convolution... # Start by checking if all objects have a hard edge. hard_edge = True for obj in args: if not obj.hasHardEdges(): hard_edge = False if real_space is None: # The automatic determination is to use real_space if 2 items, both with hard edges. if len(args) == 2: real_space = hard_edge else: real_space = False # Warn if doing DFT convolution for objects with hard edges. if not real_space and hard_edge: import warnings if len(args) == 2: msg = """ Doing convolution of 2 objects, both with hard edges. This might be more accurate and/or faster using real_space=True""" else: msg = """ Doing convolution where all objects have hard edges. There might be some inaccuracies due to ringing in k-space.""" warnings.warn(msg) if real_space: # Can't do real space if nobj > 2 if len(args) > 2: import warnings msg = """ Real-space convolution of more than 2 objects is not implemented. Switching to DFT method.""" warnings.warn(msg) real_space = False # Also can't do real space if any object is not analytic, so check for that. else: for obj in args: if not obj.isAnalyticX(): import warnings msg = """ A component to be convolved is not analytic in real space. Cannot use real space convolution. Switching to DFT method.""" warnings.warn(msg) real_space = False break # If one of the objects has a noise attribute, then we convolve it by the others. # More than one is not allowed. noise = None noise_convolve = [] for obj in args: if hasattr(obj,'noise'): if noise is not None: import warnings warnings.warn("Unable to propagate noise in galsim.Convolve when multiple "+ "objects have noise attribute") noise = None break noise = obj.noise others = [ obj2 for obj2 in args if obj2 is not obj ] assert len(others) > 0 if len(others) == 1: noise.convolveWith(others[0]) else: noise.convolveWith(galsim.Convolve(others)) # Then finally initialize the SBProfile using the objects' SBProfiles. SBList = [ obj.SBProfile for obj in args ] GSObject.__init__(self, galsim.SBConvolve(SBList, real_space=real_space, gsparams=gsparams)) if noise is not None: self.noise = noise
def __init__(self, image, x_interpolant=None, k_interpolant=None, normalization='flux', scale=None, wcs=None, flux=None, pad_factor=4., noise_pad_size=0, noise_pad=0., rng=None, pad_image=None, calculate_stepk=True, calculate_maxk=True, use_cache=True, use_true_center=True, offset=None, gsparams=None, dx=None, _force_stepk=0., _force_maxk=0.): # Check for obsolete dx parameter if dx is not None and scale is None: from galsim.deprecated import depr depr('dx', 1.1, 'scale') scale = dx # first try to read the image as a file. If it's not either a string or a valid # pyfits hdu or hdulist, then an exception will be raised, which we ignore and move on. try: image = galsim.fits.read(image) except: pass # make sure image is really an image and has a float type if not isinstance(image, galsim.Image): raise ValueError("Supplied image is not an Image instance") if image.dtype != np.float32 and image.dtype != np.float64: raise ValueError("Supplied image does not have dtype of float32 or float64!") # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor if not image.bounds.isDefined(): raise ValueError("Supplied image does not have bounds defined!") # check what normalization was specified for the image: is it an image of surface # brightness, or flux? if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+ "'f', 'surface brightness', or 'sb'.") % normalization) # set up the interpolants if none was provided by user, or check that the user-provided ones # are of a valid type if x_interpolant is None: self.x_interpolant = galsim.Quintic(tol=1e-4) else: self.x_interpolant = galsim.utilities.convert_interpolant(x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.Quintic(tol=1e-4) else: self.k_interpolant = galsim.utilities.convert_interpolant(k_interpolant) # Store the image as an attribute and make sure we don't change the original image # in anything we do here. (e.g. set scale, etc.) self.image = image.view() self.use_cache = use_cache # Set the wcs if necessary if scale is not None: if wcs is not None: raise TypeError("Cannot provide both scale and wcs to InterpolatedImage") self.image.wcs = galsim.PixelScale(scale) elif wcs is not None: if not isinstance(wcs, galsim.BaseWCS): raise TypeError("wcs parameter is not a galsim.BaseWCS instance") self.image.wcs = wcs elif self.image.wcs is None: raise ValueError("No information given with Image or keywords about pixel scale!") # Set up the GaussianDeviate if not provided one, or check that the user-provided one is # of a valid type. if rng is None: if noise_pad: rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("rng provided to InterpolatedImage constructor is not a BaseDeviate") # Check that given pad_image is valid: if pad_image: if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if not isinstance(pad_image, galsim.Image): raise ValueError("Supplied pad_image is not an Image!") if pad_image.dtype != np.float32 and pad_image.dtype != np.float64: raise ValueError("Supplied pad_image is not one of the allowed types!") # Check that the given noise_pad is valid: try: noise_pad = float(noise_pad) except: pass if isinstance(noise_pad, float): if noise_pad < 0.: raise ValueError("Noise variance cannot be negative!") # There are other options for noise_pad, the validity of which will be checked in # the helper function self.buildNoisePadImage() # This will be passed to SBInterpolatedImage, so make sure it is the right type. pad_factor = float(pad_factor) if pad_factor <= 0.: raise ValueError("Invalid pad_factor <= 0 in InterpolatedImage") if use_true_center: im_cen = self.image.bounds.trueCenter() else: im_cen = self.image.bounds.center() local_wcs = self.image.wcs.local(image_pos = im_cen) self.min_scale = local_wcs.minLinearScale() self.max_scale = local_wcs.maxLinearScale() # Make sure the image fits in the noise pad image: if noise_pad_size: import math # Convert from arcsec to pixels according to the local wcs. # Use the minimum scale, since we want to make sure noise_pad_size is # as large as we need in any direction. noise_pad_size = int(math.ceil(noise_pad_size / self.min_scale)) # Round up to a good size for doing FFTs noise_pad_size = galsim._galsim.goodFFTSize(noise_pad_size) if noise_pad_size <= min(self.image.array.shape): # Don't need any noise padding in this case. noise_pad_size = 0 elif noise_pad_size < max(self.image.array.shape): noise_pad_size = max(self.image.array.shape) # See if we need to pad out the image with either a pad_image or noise_pad if noise_pad_size: new_pad_image = self.buildNoisePadImage(noise_pad_size, noise_pad, rng) if pad_image: # if both noise_pad and pad_image are set, then we need to build up a larger # pad_image and place the given pad_image in the center. # We will change the bounds here, so make a new view to avoid modifying the # input pad_image. pad_image = pad_image.view() pad_image.setCenter(0,0) new_pad_image.setCenter(0,0) if new_pad_image.bounds.includes(pad_image.bounds): new_pad_image[pad_image.bounds] = pad_image else: new_pad_image = pad_image pad_image = new_pad_image elif pad_image: # Just make sure pad_image is the right type pad_image = galsim.Image(pad_image, dtype=image.dtype) # Now place the given image in the center of the padding image: if pad_image: pad_image.setCenter(0,0) self.image.setCenter(0,0) if pad_image.bounds.includes(self.image.bounds): pad_image[self.image.bounds] = self.image pad_image.wcs = self.image.wcs else: # If padding was smaller than original image, just use the original image. pad_image = self.image else: pad_image = self.image # GalSim cannot automatically know what stepK and maxK are appropriate for the # input image. So it is usually worth it to do a manual calculation (below). # # However, there is also a hidden option to force it to use specific values of stepK and # maxK (caveat user!). The values of _force_stepk and _force_maxk should be provided in # terms of physical scale, e.g., for images that have a scale length of 0.1 arcsec, the # stepK and maxK should be provided in units of 1/arcsec. Then we convert to the 1/pixel # units required by the C++ layer below. Also note that profile recentering for even-sized # images (see the ._fix_center step below) leads to automatic reduction of stepK slightly # below what is provided here, while maxK is preserved. if _force_stepk > 0.: calculate_stepk = False _force_stepk *= self.min_scale if _force_maxk > 0.: calculate_maxk = False _force_maxk *= self.max_scale # Save these values for pickling self._pad_image = pad_image self._pad_factor = pad_factor self._gsparams = gsparams # Make the SBInterpolatedImage out of the image. sbii = galsim._galsim.SBInterpolatedImage( pad_image.image, self.x_interpolant, self.k_interpolant, pad_factor, _force_stepk, _force_maxk, gsparams) if calculate_stepk: if calculate_stepk is True: sbii.calculateStepK() else: # If not a bool, then value is max_stepk sbii.calculateStepK(max_stepk=calculate_stepk) if calculate_maxk: if calculate_maxk is True: sbii.calculateMaxK() else: # If not a bool, then value is max_maxk sbii.calculateMaxK(max_maxk=calculate_maxk) # If the user specified a surface brightness normalization for the input Image, then # need to rescale flux by the pixel area to get proper normalization. if flux is None and normalization.lower() in ['surface brightness','sb']: flux = sbii.getFlux() * local_wcs.pixelArea() # Save this intermediate profile self._sbii = sbii self._stepk = sbii.stepK() / self.min_scale self._maxk = sbii.maxK() / self.max_scale self._flux = flux prof = GSObject(sbii) # Make sure offset is a PositionD offset = prof._parse_offset(offset) # Apply the offset, and possibly fix the centering for even-sized images # Note reverse=True, since we want to fix the center in the opposite sense of what the # draw function does. prof = prof._fix_center(self.image.array.shape, offset, use_true_center, reverse=True) # Save the offset we will need when pickling. if hasattr(prof, 'offset'): self._offset = -prof.offset else: self._offset = None # Bring the profile from image coordinates into world coordinates prof = local_wcs.toWorld(prof) # If the user specified a flux, then set to that flux value. if flux is not None: prof = prof.withFlux(float(flux)) # Now, in order for these to pickle correctly if they are the "original" object in a # Transform object, we need to hide the current transformation. An easy way to do that # is to hide the SBProfile in an SBAdd object. sbp = galsim._galsim.SBAdd([prof.SBProfile]) GSObject.__init__(self, sbp)
def setSigma(self, sigma): bvec = self.SBProfile.getBVec() GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def setPQ(self,p,q,re,im=0.): sigma = self.SBProfile.getSigma() bvec = self.SBProfile.getBVec().copy() bvec.setPQ(p,q,re,im) GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def scaleFlux(self, fluxRatio): # More efficient to change the bvector rather than add a transformation layer above # the SBShapelet, which is what the normal setFlux method does. sigma = self.SBProfile.getSigma() bvec = self.SBProfile.getBVec() * fluxRatio GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def __init__(self, real_galaxy_catalog, index=None, id=None, random=False, rng=None, x_interpolant=None, k_interpolant=None, flux=None, pad_factor=4, noise_pad_size=0, gsparams=None, logger=None): import numpy as np if rng is None: rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("The rng provided to RealGalaxy constructor is not a BaseDeviate") # Code block below will be for galaxy selection; not all are currently implemented. Each # option must return an index within the real_galaxy_catalog. if index is not None: if id is not None or random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = index elif id is not None: if random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = real_galaxy_catalog.getIndexForID(id) elif random is True: uniform_deviate = galsim.UniformDeviate(rng) use_index = int(real_galaxy_catalog.nobjects * uniform_deviate()) else: raise AttributeError('No method specified for selecting a galaxy!') if logger: logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index) # read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. self.gal_image = real_galaxy_catalog.getGal(use_index) if logger: logger.debug('RealGalaxy %d: Got gal_image',use_index) self.psf_image = real_galaxy_catalog.getPSF(use_index) if logger: logger.debug('RealGalaxy %d: Got psf_image',use_index) #self.noise = real_galaxy_catalog.getNoise(use_index, rng, gsparams) # This is a duplication of the RealGalaxyCatalog.getNoise() function, since we # want it to be possible to have the RealGalaxyCatalog in another process, and the # BaseCorrelatedNoise object is not picklable. So we just build it here instead. noise_image, pixel_scale, var = real_galaxy_catalog.getNoiseProperties(use_index) if logger: logger.debug('RealGalaxy %d: Got noise_image',use_index) if noise_image is None: self.noise = galsim.UncorrelatedNoise(var, rng=rng, scale=pixel_scale, gsparams=gsparams) else: ii = galsim.InterpolatedImage(noise_image, scale=pixel_scale, normalization="sb", calculate_stepk=False, calculate_maxk=False, x_interpolant='linear', gsparams=gsparams) self.noise = galsim.correlatednoise._BaseCorrelatedNoise(rng, ii) self.noise = self.noise.withVariance(var) if logger: logger.debug('RealGalaxy %d: Finished building noise',use_index) # Save any other relevant information as instance attributes self.catalog_file = real_galaxy_catalog.getFileName() self.index = use_index self.pixel_scale = float(pixel_scale) # Convert noise_pad to the right noise to pass to InterpolatedImage if noise_pad_size: noise_pad = self.noise else: noise_pad = 0. # Build the InterpolatedImage of the PSF. self.original_psf = galsim.InterpolatedImage( self.psf_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, flux=1.0, scale=self.pixel_scale, gsparams=gsparams) if logger: logger.debug('RealGalaxy %d: Made original_psf',use_index) # Build the InterpolatedImage of the galaxy. # Use the stepK() value of the PSF as a maximum value for stepK of the galaxy. # (Otherwise, low surface brightness galaxies can get a spuriously high stepk, which # leads to problems.) self.original_image = galsim.InterpolatedImage( self.gal_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, scale=self.pixel_scale, pad_factor=pad_factor, noise_pad_size=noise_pad_size, calculate_stepk=self.original_psf.stepK(), calculate_maxk=self.original_psf.maxK(), noise_pad=noise_pad, rng=rng, gsparams=gsparams) if logger: logger.debug('RealGalaxy %d: Made original_image',use_index) # If flux is None, leave flux as given by original image if flux != None: self.original_image = self.original_image.withFlux(flux) # Calculate the PSF "deconvolution" kernel psf_inv = galsim.Deconvolve(self.original_psf, gsparams=gsparams) # Initialize the SBProfile attribute GSObject.__init__( self, galsim.Convolve([self.original_image, psf_inv], gsparams=gsparams)) if logger: logger.debug('RealGalaxy %d: Made gsobject',use_index) # Save the noise in the image as an accessible attribute self.noise = self.noise.convolvedWith(psf_inv, gsparams) if logger: logger.debug('RealGalaxy %d: Finished building RealGalaxy',use_index)
def setSigma(self,sigma): """This method is discouraged and will be deprecated.""" GSObject.__init__(self, galsim._galsim.SBShapelet(sigma, self.SBProfile.getBVec()))
def __init__(self, image, x_interpolant = None, k_interpolant = None, normalization = 'flux', dx = None, flux = None, pad_factor = 0., noise_pad = 0., rng = None, pad_image = None, calculate_stepk=True, calculate_maxk=True, use_cache=True, use_true_center=True, offset=None, gsparams=None): # first try to read the image as a file. If it's not either a string or a valid # pyfits hdu or hdulist, then an exception will be raised, which we ignore and move on. try: image = galsim.fits.read(image) except: pass # make sure image is really an image and has a float type if not isinstance(image, galsim.BaseImageF) and not isinstance(image, galsim.BaseImageD): raise ValueError("Supplied image is not an image of floats or doubles!") # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor if not image.bounds.isDefined(): raise ValueError("Supplied image does not have bounds defined!") # check what normalization was specified for the image: is it an image of surface # brightness, or flux? if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+ "'f', 'surface brightness', or 'sb'.") % normalization) # set up the interpolants if none was provided by user, or check that the user-provided ones # are of a valid type if x_interpolant is None: self.x_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) else: self.x_interpolant = galsim.utilities.convert_interpolant_to_2d(x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) else: self.k_interpolant = galsim.utilities.convert_interpolant_to_2d(k_interpolant) # Check for input dx, and check whether Image already has one set. At the end of this # code block, either an exception will have been raised, or the input image will have a # valid scale set. if dx is None: dx = image.scale if dx == 0: raise ValueError("No information given with Image or keywords about pixel scale!") else: if type(dx) != float: dx = float(dx) if dx <= 0.0: raise ValueError("dx may not be <= 0.0") # Don't change the original image. Make a new view if we need to set the scale. image = image.view() image.scale = dx # Set up the GaussianDeviate if not provided one, or check that the user-provided one is # of a valid type. if rng is None: if noise_pad: rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("rng provided to InterpolatedImage constructor is not a BaseDeviate") # Check that given pad_image is valid: if pad_image: if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if ( not isinstance(pad_image, galsim.BaseImageF) and not isinstance(pad_image, galsim.BaseImageD) ): raise ValueError("Supplied pad_image is not one of the allowed types!") # Check that the given noise_pad is valid: try: noise_pad = float(noise_pad) except: pass if isinstance(noise_pad, float): if noise_pad < 0.: raise ValueError("Noise variance cannot be negative!") # There are other options for noise_pad, the validity of which will be checked in # the helper function self.buildNoisePadImage() # This will be passed to SBInterpolatedImage, so make sure it is the right type. pad_factor = float(pad_factor) # Store the image as an attribute self.orig_image = image self.use_cache = use_cache # See if we need to build a pad_image if noise_pad and pad_image: # if both noise_pad and pad_image are set, then we need to build up a larger # pad_image and place the given pad_image in the center. new_pad_image = self.buildNoisePadImage(pad_factor, noise_pad, rng) # We will change the bounds here, so make a new view to avoid modifying the # input pad_image. pad_image = pad_image.view() pad_image.setCenter(0,0) new_pad_image.setCenter(0,0) if not new_pad_image.bounds.includes(pad_image.bounds): raise ValueError("pad_factor is too small to fit the provided pad_image.") new_pad_image[pad_image.bounds] = pad_image pad_image = new_pad_image elif noise_pad: # Just build the noise image pad_image = self.buildNoisePadImage(pad_factor, noise_pad, rng) elif pad_image: # Just make sure pad_image is the right type if ( isinstance(image, galsim.BaseImageF) and not isinstance(pad_image, galsim.BaseImageF) ): pad_image = galsim.ImageF(pad_image) elif ( isinstance(image, galsim.BaseImageD) and not isinstance(pad_image, galsim.BaseImageD) ): pad_image = galsim.ImageD(pad_image) # Make the SBInterpolatedImage out of the image. sbinterpolatedimage = galsim.SBInterpolatedImage( image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=dx, pad_factor=pad_factor, pad_image=pad_image, gsparams=gsparams) # GalSim cannot automatically know what stepK and maxK are appropriate for the # input image. So it is usually worth it to do a manual calculation here. if calculate_stepk: sbinterpolatedimage.calculateStepK() if calculate_maxk: sbinterpolatedimage.calculateMaxK() # If the user specified a flux, then set to that flux value. if flux != None: if type(flux) != flux: flux = float(flux) sbinterpolatedimage.setFlux(flux) # If the user specified a flux normalization for the input Image, then since # SBInterpolatedImage works in terms of surface brightness, have to rescale the values to # get proper normalization. elif flux is None and normalization.lower() in ['flux','f'] and dx != 1.: sbinterpolatedimage.scaleFlux(1./(dx**2)) # If the input Image normalization is 'sb' then since that is the SBInterpolated default # assumption, no rescaling is needed. # Initialize the SBProfile GSObject.__init__(self, sbinterpolatedimage) # Apply the offset, and possibly fix the centering for even-sized images # Note reverse=True, since we want to fix the center in the opposite sense of what the # draw function does. prof = self._fix_center(image, dx, offset, use_true_center, reverse=True) GSObject.__init__(self, prof.SBProfile)
def __init__(self, real_galaxy_catalog, index=None, id=None, random=False, rng=None, x_interpolant=None, k_interpolant=None, flux=None, pad_factor=0, noise_pad=False, pad_image=None, use_cache=True, gsparams=None): import pyfits import numpy as np # Code block below will be for galaxy selection; not all are currently implemented. Each # option must return an index within the real_galaxy_catalog. if index is not None: if id is not None or random is True: raise AttributeError( 'Too many methods for selecting a galaxy!') use_index = index elif id is not None: if random is True: raise AttributeError( 'Too many methods for selecting a galaxy!') use_index = real_galaxy_catalog._get_index_for_id(id) elif random is True: if rng is None: uniform_deviate = galsim.UniformDeviate() elif isinstance(rng, galsim.BaseDeviate): uniform_deviate = galsim.UniformDeviate(rng) else: raise TypeError( "The rng provided to RealGalaxy constructor is not a BaseDeviate" ) use_index = int(real_galaxy_catalog.nobjects * uniform_deviate()) else: raise AttributeError('No method specified for selecting a galaxy!') # read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. Should # consider exporting this code into fits.py in some function that takes a filename and HDU, # and returns an ImageView gal_image = real_galaxy_catalog.getGal(use_index) PSF_image = real_galaxy_catalog.getPSF(use_index) # choose proper interpolant if x_interpolant is None: lan5 = galsim.Lanczos(5, conserve_flux=True, tol=1.e-4) self.x_interpolant = galsim.InterpolantXY(lan5) else: self.x_interpolant = galsim.utilities.convert_interpolant_to_2d( x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.InterpolantXY( galsim.Quintic(tol=1.e-4)) else: self.k_interpolant = galsim.utilities.convert_interpolant_to_2d( k_interpolant) # read in data about galaxy from FITS binary table; store as normal attributes of RealGalaxy # save any other relevant information as instance attributes self.catalog_file = real_galaxy_catalog.file_name self.index = use_index self.pixel_scale = float(real_galaxy_catalog.pixel_scale[use_index]) # handle padding by an image specify_size = False padded_size = gal_image.getPaddedSize(pad_factor) if pad_image is not None: specify_size = True if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if (not isinstance(pad_image, galsim.BaseImageF) and not isinstance(pad_image, galsim.BaseImageD)): raise ValueError( "Supplied pad_image is not one of the allowed types!") # If an image was supplied directly or from a file, check its size: # Cannot use if too small. # Use to define the final image size otherwise. deltax = ((1 + pad_image.getXMax() - pad_image.getXMin()) - (1 + gal_image.getXMax() - gal_image.getXMin())) deltay = ((1 + pad_image.getYMax() - pad_image.getYMin()) - (1 + gal_image.getYMax() - gal_image.getYMin())) if deltax < 0 or deltay < 0: raise RuntimeError("Image supplied for padding is too small!") if pad_factor != 1. and pad_factor != 0.: import warnings msg = "Warning: ignoring specified pad_factor because user also specified\n" msg += " an image to use directly for the padding." warnings.warn(msg) else: if isinstance(gal_image, galsim.BaseImageF): pad_image = galsim.ImageF(padded_size, padded_size) if isinstance(gal_image, galsim.BaseImageD): pad_image = galsim.ImageD(padded_size, padded_size) # Set up the GaussianDeviate if not provided one, or check that the user-provided one # is of a valid type. Note if random was selected, we can use that uniform_deviate safely. if random is True: gaussian_deviate = galsim.GaussianDeviate(uniform_deviate) else: if rng is None: gaussian_deviate = galsim.GaussianDeviate() elif isinstance(rng, galsim.BaseDeviate): # Even if it's already a GaussianDeviate, we still want to make a new Gaussian # deviate that would generate the same sequence, because later we change the sigma # and we don't want to change it for the original one that was passed in. So don't # distinguish between GaussianDeviate and the other BaseDeviates here. gaussian_deviate = galsim.GaussianDeviate(rng) else: raise TypeError( "rng provided to RealGalaxy constructor is not a BaseDeviate" ) # handle noise-padding options try: noise_pad = galsim.config.value._GetBoolValue(noise_pad, '') except: pass if noise_pad: self.pad_variance = float(real_galaxy_catalog.variance[use_index]) # Check, is it "True" or something else? If True, we use Gaussian uncorrelated noise # using the stored variance in the catalog. Otherwise, if it's a CorrelatedNoise we use # it directly; if it's an Image of some sort we use it to make a CorrelatedNoise; if # it's a string, we read in the image from file and make a CorrelatedNoise. if type(noise_pad) is not bool: if isinstance(noise_pad, galsim.correlatednoise._BaseCorrelatedNoise): cn = noise_pad.copy() if rng: # Let user supplied RNG take precedence over that in user CN cn.setRNG(gaussian_deviate) # This small patch may have different overall variance, so rescale while # preserving the correlation structure by default cn.setVariance(self.pad_variance) elif (isinstance(noise_pad, galsim.BaseImageF) or isinstance(noise_pad, galsim.BaseImageD)): cn = galsim.CorrelatedNoise(gaussian_deviate, noise_pad) elif use_cache and noise_pad in RealGalaxy._cache_noise_pad: cn = RealGalaxy._cache_noise_pad[noise_pad] # Make sure that we are using the desired RNG by resetting that in this cached # CorrelatedNoise instance if rng: cn.setRNG(gaussian_deviate) # This small patch may have different overall variance, so rescale while # preserving the correlation structure cn.setVariance(self.pad_variance) elif isinstance(noise_pad, str): tmp_img = galsim.fits.read(noise_pad) cn = galsim.CorrelatedNoise(gaussian_deviate, tmp_img) if use_cache: RealGalaxy._cache_noise_pad[noise_pad] = cn # This small patch may have different overall variance, so rescale while # preserving the correlation structure cn.setVariance(self.pad_variance) else: raise RuntimeError( "noise_pad must be either a bool, CorrelatedNoise, Image, " + "or a filename for reading in an Image") # Set the GaussianDeviate sigma gaussian_deviate.setSigma(np.sqrt(self.pad_variance)) # populate padding image with noise field if type(noise_pad) is bool: pad_image.addNoise(galsim.DeviateNoise(gaussian_deviate)) else: pad_image.addNoise(cn) else: self.pad_variance = 0. # Now we have to check: was the padding determined using pad_factor? Or by passing in an # image for padding? Treat these cases differently: # (1) If the former, then we can simply have the C++ handle the padding process. # (2) If the latter, then we have to do the padding ourselves, and pass the resulting image # to the C++ with pad_factor explicitly set to 1. if specify_size is False: # Make the SBInterpolatedImage out of the image. self.original_image = galsim.SBInterpolatedImage( gal_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=self.pixel_scale, pad_factor=pad_factor, pad_image=pad_image, gsparams=gsparams) else: # Leave the original image as-is. Instead, we shift around the image to be used for # padding. Find out how much x and y margin there should be on lower end: x_marg = int(np.round(0.5 * deltax)) y_marg = int(np.round(0.5 * deltay)) # Now reset the pad_image to contain the original image in an even way pad_image = pad_image.view() pad_image.setScale(self.pixel_scale) pad_image.setOrigin(gal_image.getXMin() - x_marg, gal_image.getYMin() - y_marg) # Set the central values of pad_image to be equal to the input image pad_image[gal_image.bounds] = gal_image self.original_image = galsim.SBInterpolatedImage( pad_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=self.pixel_scale, pad_factor=1., gsparams=gsparams) # also make the original PSF image, with far less fanfare: we don't need to pad with # anything interesting. self.original_PSF = galsim.SBInterpolatedImage( PSF_image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, dx=self.pixel_scale, gsparams=gsparams) # recalculate Fourier-space attributes rather than using overly-conservative defaults self.original_image.calculateStepK() self.original_image.calculateMaxK() self.original_PSF.calculateStepK() self.original_PSF.calculateMaxK() if flux != None: self.original_image.setFlux(flux) self.original_image.__class__ = galsim.SBTransform # correctly reflect SBProfile change self.original_PSF.setFlux(1.0) self.original_PSF.__class__ = galsim.SBTransform # correctly reflect SBProfile change # Calculate the PSF "deconvolution" kernel psf_inv = galsim.SBDeconvolve(self.original_PSF, gsparams=gsparams) # Initialize the SBProfile attribute GSObject.__init__( self, galsim.SBConvolve([self.original_image, psf_inv], gsparams=gsparams))
def __init__(self, real_galaxy_catalog, index=None, id=None, random=False, rng=None, x_interpolant=None, k_interpolant=None, flux=None, flux_rescale=None, pad_factor=4, noise_pad_size=0, gsparams=None, logger=None): if rng is None: self.rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("The rng provided to RealGalaxy constructor is not a BaseDeviate") else: self.rng = rng self._rng = self.rng.duplicate() # This is only needed if we want to make sure eval(repr) # results in the same object. if flux is not None and flux_rescale is not None: raise TypeError("Cannot supply a flux and a flux rescaling factor!") if isinstance(real_galaxy_catalog, tuple): # Special (undocumented) way to build a RealGalaxy without needing the rgc directly # by providing the things we need from it. Used by COSMOSGalaxy. self.gal_image, self.psf_image, noise_image, pixel_scale, var = real_galaxy_catalog use_index = 0 # For the logger statements below. if logger: logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index) self.catalog_file = None else: # Get the index to use in the catalog if index is not None: if id is not None or random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = index elif id is not None: if random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = real_galaxy_catalog.getIndexForID(id) elif random: ud = galsim.UniformDeviate(self.rng) use_index = int(real_galaxy_catalog.nobjects * ud()) if hasattr(real_galaxy_catalog, 'weight'): # If weight factors are available, make sure the random selection uses the # weights to remove the catalog-level selection effects (flux_radius-dependent # probability of making a postage stamp for a given object). while ud() > real_galaxy_catalog.weight[use_index]: # Pick another one to try. use_index = int(real_galaxy_catalog.nobjects * ud()) else: raise AttributeError('No method specified for selecting a galaxy!') if logger: logger.debug('RealGalaxy %d: Start RealGalaxy constructor.',use_index) # Read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. self.gal_image = real_galaxy_catalog.getGal(use_index) if logger: logger.debug('RealGalaxy %d: Got gal_image',use_index) self.psf_image = real_galaxy_catalog.getPSF(use_index) if logger: logger.debug('RealGalaxy %d: Got psf_image',use_index) #self.noise = real_galaxy_catalog.getNoise(use_index, self.rng, gsparams) # We need to duplication some of the RealGalaxyCatalog.getNoise() function, since we # want it to be possible to have the RealGalaxyCatalog in another process, and the # BaseCorrelatedNoise object is not picklable. So we just build it here instead. noise_image, pixel_scale, var = real_galaxy_catalog.getNoiseProperties(use_index) if logger: logger.debug('RealGalaxy %d: Got noise_image',use_index) self.catalog_file = real_galaxy_catalog.getFileName() if noise_image is None: self.noise = galsim.UncorrelatedNoise(var, rng=self.rng, scale=pixel_scale, gsparams=gsparams) else: ii = galsim.InterpolatedImage(noise_image, normalization="sb", calculate_stepk=False, calculate_maxk=False, x_interpolant='linear', gsparams=gsparams) self.noise = galsim.correlatednoise._BaseCorrelatedNoise(self.rng, ii, noise_image.wcs) self.noise = self.noise.withVariance(var) if logger: logger.debug('RealGalaxy %d: Finished building noise',use_index) # Save any other relevant information as instance attributes self.catalog = real_galaxy_catalog self.index = use_index self.pixel_scale = float(pixel_scale) self._x_interpolant = x_interpolant self._k_interpolant = k_interpolant self._pad_factor = pad_factor self._noise_pad_size = noise_pad_size self._flux = flux self._gsparams = gsparams # Convert noise_pad to the right noise to pass to InterpolatedImage if noise_pad_size: noise_pad = self.noise else: noise_pad = 0. # Build the InterpolatedImage of the PSF. self.original_psf = galsim.InterpolatedImage( self.psf_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, flux=1.0, gsparams=gsparams) if logger: logger.debug('RealGalaxy %d: Made original_psf',use_index) # Build the InterpolatedImage of the galaxy. # Use the stepK() value of the PSF as a maximum value for stepK of the galaxy. # (Otherwise, low surface brightness galaxies can get a spuriously high stepk, which # leads to problems.) self.original_gal = galsim.InterpolatedImage( self.gal_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, pad_factor=pad_factor, noise_pad_size=noise_pad_size, calculate_stepk=self.original_psf.stepK(), calculate_maxk=self.original_psf.maxK(), noise_pad=noise_pad, rng=self.rng, gsparams=gsparams) if logger: logger.debug('RealGalaxy %d: Made original_gal',use_index) # If flux is None, leave flux as given by original image if flux is not None: flux_rescale = flux / self.original_gal.getFlux() if flux_rescale is not None: self.original_gal *= flux_rescale self.noise *= flux_rescale**2 # Calculate the PSF "deconvolution" kernel psf_inv = galsim.Deconvolve(self.original_psf, gsparams=gsparams) # Initialize the SBProfile attribute GSObject.__init__( self, galsim.Convolve([self.original_gal, psf_inv], gsparams=gsparams)) if logger: logger.debug('RealGalaxy %d: Made gsobject',use_index) # Save the noise in the image as an accessible attribute self.noise = self.noise.convolvedWith(psf_inv, gsparams) if logger: logger.debug('RealGalaxy %d: Finished building RealGalaxy',use_index)
def setSigma(self,sigma): bvec = self.SBProfile.getBVec() GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
def setPQ(self,p,q,re,im=0.): """This method is discouraged and will be deprecated.""" bvec = self.SBProfile.getBVec().copy() bvec.setPQ(p,q,re,im) GSObject.__init__(self, galsim._galsim.SBShapelet(self.sigma, bvec))
def __init__(self, image, x_interpolant=None, k_interpolant=None, normalization='flux', scale=None, wcs=None, flux=None, pad_factor=4., noise_pad_size=0, noise_pad=0., rng=None, pad_image=None, calculate_stepk=True, calculate_maxk=True, use_cache=True, use_true_center=True, offset=None, gsparams=None, dx=None): # Check for obsolete dx parameter if dx is not None and scale is None: scale = dx import numpy # first try to read the image as a file. If it's not either a string or a valid # pyfits hdu or hdulist, then an exception will be raised, which we ignore and move on. try: image = galsim.fits.read(image) except: pass # make sure image is really an image and has a float type if not isinstance(image, galsim.Image): raise ValueError("Supplied image is not an Image instance") if image.dtype != numpy.float32 and image.dtype != numpy.float64: raise ValueError("Supplied image is not an image of floats or doubles!") # it must have well-defined bounds, otherwise seg fault in SBInterpolatedImage constructor if not image.bounds.isDefined(): raise ValueError("Supplied image does not have bounds defined!") # check what normalization was specified for the image: is it an image of surface # brightness, or flux? if not normalization.lower() in ("flux", "f", "surface brightness", "sb"): raise ValueError(("Invalid normalization requested: '%s'. Expecting one of 'flux', "+ "'f', 'surface brightness', or 'sb'.") % normalization) # set up the interpolants if none was provided by user, or check that the user-provided ones # are of a valid type if x_interpolant is None: self.x_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) else: self.x_interpolant = galsim.utilities.convert_interpolant_to_2d(x_interpolant) if k_interpolant is None: self.k_interpolant = galsim.InterpolantXY(galsim.Quintic(tol=1e-4)) else: self.k_interpolant = galsim.utilities.convert_interpolant_to_2d(k_interpolant) # Store the image as an attribute and make sure we don't change the original image # in anything we do here. (e.g. set scale, etc.) self.image = image.view() self.use_cache = use_cache # Set the wcs if necessary if scale is not None: if wcs is not None: raise TypeError("Cannot provide both scale and wcs to InterpolatedImage") self.image.wcs = galsim.PixelScale(scale) elif wcs is not None: if not isinstance(wcs, galsim.BaseWCS): raise TypeError("wcs parameter is not a galsim.BaseWCS instance") self.image.wcs = wcs elif self.image.wcs is None: raise ValueError("No information given with Image or keywords about pixel scale!") # Set up the GaussianDeviate if not provided one, or check that the user-provided one is # of a valid type. if rng is None: if noise_pad: rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("rng provided to InterpolatedImage constructor is not a BaseDeviate") # Check that given pad_image is valid: if pad_image: import numpy if isinstance(pad_image, str): pad_image = galsim.fits.read(pad_image) if not isinstance(pad_image, galsim.Image): raise ValueError("Supplied pad_image is not an Image!") if pad_image.dtype != numpy.float32 and pad_image.dtype != numpy.float64: raise ValueError("Supplied pad_image is not one of the allowed types!") # Check that the given noise_pad is valid: try: noise_pad = float(noise_pad) except: pass if isinstance(noise_pad, float): if noise_pad < 0.: raise ValueError("Noise variance cannot be negative!") # There are other options for noise_pad, the validity of which will be checked in # the helper function self.buildNoisePadImage() # This will be passed to SBInterpolatedImage, so make sure it is the right type. pad_factor = float(pad_factor) if pad_factor <= 0.: raise ValueError("Invalid pad_factor <= 0 in InterpolatedImage") if use_true_center: im_cen = self.image.bounds.trueCenter() else: im_cen = self.image.bounds.center() local_wcs = self.image.wcs.local(image_pos = im_cen) # Make sure the image fits in the noise pad image: if noise_pad_size: import math # Convert from arcsec to pixels according to the local wcs. # Use the minimum scale, since we want to make sure noise_pad_size is # as large as we need in any direction. scale = local_wcs.minLinearScale() noise_pad_size = int(math.ceil(noise_pad_size / scale)) # Round up to a good size for doing FFTs noise_pad_size = galsim._galsim.goodFFTSize(noise_pad_size) if noise_pad_size <= min(self.image.array.shape): # Don't need any noise padding in this case. noise_pad_size = 0 elif noise_pad_size < max(self.image.array.shape): noise_pad_size = max(self.image.array.shape) # See if we need to pad out the image with either a pad_image or noise_pad if noise_pad_size: new_pad_image = self.buildNoisePadImage(noise_pad_size, noise_pad, rng) if pad_image: # if both noise_pad and pad_image are set, then we need to build up a larger # pad_image and place the given pad_image in the center. # We will change the bounds here, so make a new view to avoid modifying the # input pad_image. pad_image = pad_image.view() pad_image.setCenter(0,0) new_pad_image.setCenter(0,0) if new_pad_image.bounds.includes(pad_image.bounds): new_pad_image[pad_image.bounds] = pad_image else: new_pad_image = pad_image pad_image = new_pad_image elif pad_image: # Just make sure pad_image is the right type pad_image = galsim.Image(pad_image, dtype=image.dtype) # Now place the given image in the center of the padding image: if pad_image: pad_image.setCenter(0,0) self.image.setCenter(0,0) if pad_image.bounds.includes(self.image.bounds): pad_image[self.image.bounds] = self.image else: # If padding was smaller than original image, just use the original image. pad_image = self.image else: pad_image = self.image # Make the SBInterpolatedImage out of the image. sbinterpolatedimage = galsim._galsim.SBInterpolatedImage( pad_image.image, xInterp=self.x_interpolant, kInterp=self.k_interpolant, pad_factor=pad_factor, gsparams=gsparams) # GalSim cannot automatically know what stepK and maxK are appropriate for the # input image. So it is usually worth it to do a manual calculation here. if calculate_stepk: if calculate_stepk is True: sbinterpolatedimage.calculateStepK() else: # If not a bool, then value is max_stepk sbinterpolatedimage.calculateStepK(max_stepk=calculate_stepk) if calculate_maxk: if calculate_maxk is True: sbinterpolatedimage.calculateMaxK() else: # If not a bool, then value is max_maxk sbinterpolatedimage.calculateMaxK(max_maxk=calculate_maxk) # Initialize the SBProfile GSObject.__init__(self, sbinterpolatedimage) # Make sure offset is a PositionD offset = self._parse_offset(offset) # Apply the offset, and possibly fix the centering for even-sized images # Note reverse=True, since we want to fix the center in the opposite sense of what the # draw function does. prof = self._fix_center(self.image, offset, use_true_center, reverse=True) # Bring the profile from image coordinates into world coordinates prof = local_wcs.toWorld(prof) # If the user specified a flux, then set to that flux value. if flux is not None: prof = prof.withFlux(float(flux)) # If the user specified a surface brightness normalization for the input Image, then # need to rescale flux by the pixel area to get proper normalization. elif normalization.lower() in ['surface brightness','sb']: prof *= local_wcs.pixelArea() GSObject.__init__(self, prof)
def __init__(self, real_galaxy_catalog, index=None, id=None, random=False, rng=None, x_interpolant=None, k_interpolant=None, flux=None, pad_factor=0, noise_pad=False, pad_image=None, use_cache=True, gsparams=None): import pyfits import numpy as np if rng is None: rng = galsim.BaseDeviate() elif not isinstance(rng, galsim.BaseDeviate): raise TypeError("The rng provided to RealGalaxy constructor is not a BaseDeviate") # Code block below will be for galaxy selection; not all are currently implemented. Each # option must return an index within the real_galaxy_catalog. if index is not None: if id is not None or random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = index elif id is not None: if random is True: raise AttributeError('Too many methods for selecting a galaxy!') use_index = real_galaxy_catalog._get_index_for_id(id) elif random is True: uniform_deviate = galsim.UniformDeviate(rng) use_index = int(real_galaxy_catalog.nobjects * uniform_deviate()) else: raise AttributeError('No method specified for selecting a galaxy!') # read in the galaxy, PSF images; for now, rely on pyfits to make I/O errors. gal_image = real_galaxy_catalog.getGal(use_index) PSF_image = real_galaxy_catalog.getPSF(use_index) noise = real_galaxy_catalog.getNoise(use_index, rng, gsparams) # save any other relevant information as instance attributes self.catalog_file = real_galaxy_catalog.file_name self.index = use_index self.pixel_scale = float(real_galaxy_catalog.pixel_scale[use_index]) # handle noise-padding options try: noise_pad = galsim.config.value._GetBoolValue(noise_pad,'') # If it's a bool and True, use the correlated noise specified in the catalog. if noise_pad: noise_pad = noise else: noise_pad = 0. except: # If it's not a bool, or convertible to a bool, leave it alone. pass self.original_image = galsim.InterpolatedImage( gal_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, dx=self.pixel_scale, pad_factor=pad_factor, noise_pad=noise_pad, rng=rng, pad_image=pad_image, use_cache=use_cache, gsparams=gsparams) # If flux is None, leave flux as given by original image if flux != None: self.original_image.setFlux(flux) # also make the original PSF image, with far less fanfare: we don't need to pad with # anything interesting. self.original_PSF = galsim.InterpolatedImage( PSF_image, x_interpolant=x_interpolant, k_interpolant=k_interpolant, flux=1.0, dx=self.pixel_scale, gsparams=gsparams) #self.original_PSF.setFlux(1.0) # Calculate the PSF "deconvolution" kernel psf_inv = galsim.Deconvolve(self.original_PSF, gsparams=gsparams) # Initialize the SBProfile attribute GSObject.__init__( self, galsim.Convolve([self.original_image, psf_inv], gsparams=gsparams)) # Save the noise in the image as an accessible attribute noise.convolveWith(psf_inv, gsparams) self.noise = noise