Esempio n. 1
0
 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))
Esempio n. 2
0
 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))
Esempio n. 3
0
 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")
Esempio n. 4
0
    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")
Esempio n. 5
0
    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))
Esempio n. 6
0
    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))
Esempio n. 7
0
 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))
Esempio n. 8
0
 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))
Esempio n. 9
0
    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))
Esempio n. 10
0
    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))
Esempio n. 11
0
 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))
Esempio n. 12
0
 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.")
Esempio n. 13
0
    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()
Esempio n. 14
0
 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))
Esempio n. 15
0
 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))
Esempio n. 16
0
    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
Esempio n. 17
0
 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))
Esempio n. 18
0
    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))
Esempio n. 19
0
    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()
Esempio n. 20
0
 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))
Esempio n. 21
0
 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))
Esempio n. 22
0
    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))
Esempio n. 23
0
    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))
Esempio n. 24
0
    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))
Esempio n. 25
0
    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()
Esempio n. 26
0
    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
Esempio n. 27
0
    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))
Esempio n. 28
0
    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
Esempio n. 29
0
    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)
Esempio n. 30
0
    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))
Esempio n. 31
0
 def applyDilation(self, scale):
     sigma = self.SBProfile.getSigma() * scale
     bvec = self.SBProfile.getBVec()
     GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
Esempio n. 32
0
 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))
Esempio n. 33
0
 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))
Esempio n. 34
0
    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()
Esempio n. 35
0
    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)
Esempio n. 36
0
    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)
Esempio n. 37
0
    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
Esempio n. 38
0
    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)
Esempio n. 39
0
 def setSigma(self, sigma):
     bvec = self.SBProfile.getBVec()
     GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
Esempio n. 40
0
 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))
Esempio n. 41
0
 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))
Esempio n. 42
0
 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))
Esempio n. 43
0
 def applyDilation(self, scale):
     sigma = self.SBProfile.getSigma() * scale
     bvec = self.SBProfile.getBVec()
     GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
Esempio n. 44
0
    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)
Esempio n. 45
0
 def setSigma(self,sigma):
     """This method is discouraged and will be deprecated."""
     GSObject.__init__(self, galsim._galsim.SBShapelet(sigma, self.SBProfile.getBVec()))
Esempio n. 46
0
 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))
Esempio n. 47
0
    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)
Esempio n. 48
0
    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))
Esempio n. 49
0
    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)
Esempio n. 50
0
 def setSigma(self,sigma):
     bvec = self.SBProfile.getBVec()
     GSObject.__init__(self, galsim.SBShapelet(sigma, bvec))
Esempio n. 51
0
 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))
Esempio n. 52
0
 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))
Esempio n. 53
0
    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)
Esempio n. 54
0
    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