Esempio n. 1
0
def _type_by_letter(key):
    if len(key) < 2:
        raise galsim.GalSimConfigError("Invalid user-defined variable %r" %
                                       key)
    if key[0] == 'f':
        return float
    elif key[0] == 'i':
        return int
    elif key[0] == 'b':
        return bool
    elif key[0] == 's':
        return str
    elif key[0] == 'a':
        return galsim.Angle
    elif key[0] == 'p':
        return galsim.PositionD
    elif key[0] == 'c':
        return galsim.CelestialCoord
    elif key[0] == 'g':
        return galsim.Shear
    elif key[0] == 'x':
        return None
    else:
        raise galsim.GalSimConfigError(
            "Invalid Eval variable: %s (starts with an invalid letter)" % key)
Esempio n. 2
0
def _BuildConvolve(config, base, ignore, gsparams, logger):
    """Build a Convolution object.
    """
    req = { 'items' : list }
    opt = { 'flux' : float }
    # Only Check, not Get.  We need to handle items a bit differently, since it's a list.
    galsim.config.CheckAllParams(config, req=req, opt=opt, ignore=ignore)

    gsobjects = []
    items = config['items']
    if not isinstance(items,list):
        raise galsim.GalSimConfigError("items entry for type=Convolve is not a list.")
    safe = True
    for i in range(len(items)):
        gsobject, safe1 = BuildGSObject(items, i, base, gsparams, logger)
        safe = safe and safe1
        gsobjects.append(gsobject)

    if len(gsobjects) == 0:
        raise galsim.GalSimConfigError("No valid items for type=Convolve")
    elif len(gsobjects) == 1:
        gsobject = gsobjects[0]
    else:
        if gsparams: gsparams = galsim.GSParams(**gsparams)
        else: gsparams = None
        gsobject = galsim.Convolve(gsobjects,gsparams=gsparams)

    if 'flux' in config:
        flux, safe1 = galsim.config.ParseValue(config, 'flux', base, float)
        logger.debug('obj %d: flux == %f',base.get('obj_num',0),flux)
        gsobject = gsobject.withFlux(flux)
        safe = safe and safe1

    return gsobject, safe
Esempio n. 3
0
def _GenerateFromNFWHaloMagnification(config, base, value_type):
    """Return a magnification calculated from an NFWHalo object.
    """
    nfw_halo = galsim.config.GetInputObj('nfw_halo', config, base, 'NFWHaloMagnification')
    logger = nfw_halo.logger

    if 'world_pos' not in base:
        raise galsim.GalSimConfigError("NFWHaloMagnification requested, but no position defined.")
    pos = base['world_pos']

    if 'gal' not in base or 'redshift' not in base['gal']:
        raise galsim.GalSimConfigError(
            "NFWHaloMagnification requested, but no gal.redshift defined.")
    redshift = galsim.config.GetCurrentValue('redshift', base['gal'], float, base)

    opt = { 'max_mu' : float, 'num' : int }
    kwargs = galsim.config.GetAllParams(config, base, opt=opt)[0]

    max_mu = kwargs.get('max_mu', 25.)
    if not max_mu > 0.:
        raise galsim.GalSimConfigValueError(
            "Invalid max_mu for type = NFWHaloMagnification (must be > 0)", max_mu)

    mu = nfw_halo.getMagnification(pos,redshift)
    if mu < 0 or mu > max_mu:
        logger.warning('obj %d: Warning: NFWHalo mu = %f means strong lensing. '%(
                       base['obj_num'],mu) + 'Using mu = %f'%max_mu)
        mu = max_mu

    logger.debug('obj %d: NFWHalo mu = %s',base['obj_num'],mu)
    return mu, False
Esempio n. 4
0
def _GenerateFromNFWHaloShear(config, base, value_type):
    """Return a shear calculated from an NFWHalo object.
    """
    nfw_halo = galsim.config.GetInputObj('nfw_halo', config, base, 'NFWHaloShear')
    logger = nfw_halo.logger

    if 'world_pos' not in base:
        raise galsim.GalSimConfigError("NFWHaloShear requested, but no position defined.")
    pos = base['world_pos']

    if 'gal' not in base or 'redshift' not in base['gal']:
        raise galsim.GalSimConfigError("NFWHaloShear requested, but no gal.redshift defined.")
    redshift = galsim.config.GetCurrentValue('redshift', base['gal'], float, base)

    # There aren't any parameters for this, so just make sure num is the only (optional)
    # one present.
    galsim.config.CheckAllParams(config, opt={ 'num' : int })

    g1,g2 = nfw_halo.getShear(pos,redshift)

    try:
        shear = galsim.Shear(g1=g1,g2=g2)
    except KeyboardInterrupt:
        raise
    except Exception as e:
        logger.warning('obj %d: Warning: NFWHalo shear (g1=%f, g2=%f) is invalid. '%(
                       base['obj_num'],g1,g2) + 'Using shear = 0.')
        shear = galsim.Shear(g1=0,g2=0)

    logger.debug('obj %d: NFWHalo shear = %s',base['obj_num'],shear)
    return shear, False
Esempio n. 5
0
def _BuildList(config, base, ignore, gsparams, logger):
    """Build a GSObject selected from a List.
    """
    req = { 'items' : list }
    opt = { 'index' : float , 'flux' : float }
    # Only Check, not Get.  We need to handle items a bit differently, since it's a list.
    galsim.config.CheckAllParams(config, req=req, opt=opt, ignore=ignore)

    items = config['items']
    if not isinstance(items,list):
        raise galsim.GalSimConfigError("items entry for type=List is not a list.")

    # Setup the indexing sequence if it hasn't been specified using the length of items.
    galsim.config.SetDefaultIndex(config, len(items))
    index, safe = galsim.config.ParseValue(config, 'index', base, int)
    if index < 0 or index >= len(items):
        raise galsim.GalSimConfigError("index %d out of bounds for List"%index)

    gsobject, safe1 = BuildGSObject(items, index, base, gsparams, logger)
    safe = safe and safe1

    if 'flux' in config:
        flux, safe1 = galsim.config.ParseValue(config, 'flux', base, float)
        logger.debug('obj %d: flux == %f',base.get('obj_num',0),flux)
        gsobject = gsobject.withFlux(flux)
        safe = safe and safe1

    return gsobject, safe
Esempio n. 6
0
def CheckAllParams(config, req={}, opt={}, single=[], ignore=[]):
    """Check that the parameters for a particular item are all valid

    Parameters:
        config:     The config dict to check
        req:        The required items [default: {}]
        opt:        The optional items [default: {}]
        single:     List of items where exactly one is required [default: []]
        ignore:     Items to ignore [default: []]

    Returns:
        a dict, get, with get[key] = value_type for all keys to get.
    """
    if '_get' in config: return config['_get']

    get = {}
    valid_keys = list(req) + list(opt)
    # Check required items:
    for (key, value_type) in req.items():
        if key in config:
            get[key] = value_type
        else:
            raise galsim.GalSimConfigError(
                "Attribute %s is required for type = %s" %
                (key, config.get('type', None)))

    # Check optional items:
    for (key, value_type) in opt.items():
        if key in config:
            get[key] = value_type

    # Check items for which exacly 1 should be defined:
    for s in single:
        valid_keys += list(s)
        count = 0
        for (key, value_type) in s.items():
            if key in config:
                count += 1
                if count > 1:
                    raise galsim.GalSimConfigError(
                        "Only one of the attributes %s is allowed for type = %s"
                        % (s.keys(), config.get('type', None)))
                get[key] = value_type
        if count == 0:
            raise galsim.GalSimConfigError(
                "One of the attributes %s is required for type = %s" %
                (s.keys(), config.get('type', None)))

    # Check that there aren't any extra keys in config aside from a few we expect:
    valid_keys += ignore
    valid_keys += standard_ignore
    for key in config:
        # Generators are allowed to use item names that start with _, which we ignore here.
        if key not in valid_keys and not key.startswith('_'):
            raise galsim.GalSimConfigError("Unexpected attribute %s found" %
                                           (key))

    config['_get'] = get
    return get
Esempio n. 7
0
    def getSNRScale(self, image, config, base, logger):
        """Calculate the factor by which to rescale the image based on a desired S/N level.

        Note: The default implementation does this for the gal or psf field, so if a custom
              stamp builder uses some other way to get the profiles, this method should
              probably be overridden.

        Parameters:
            image:      The current image.
            config:     The configuration dict for the stamp field.
            base:       The base configuration dict.
            logger:     If given, a logger object to log progress.

        Returns:
            scale_factor
        """
        if 'gal' in base and 'signal_to_noise' in base['gal']:
            key = 'gal'
        elif 'gal' not in base and 'psf' in base and 'signal_to_noise' in base[
                'psf']:
            key = 'psf'
        else:
            return 1.

        if 'flux' in base[key]:
            raise galsim.GalSimConfigError(
                'Only one of signal_to_noise or flux may be specified for %s' %
                key)

        if 'image' in base and 'noise' in base['image']:
            noise_var = galsim.config.CalculateNoiseVariance(base)
        else:
            raise galsim.GalSimConfigError(
                "Need to specify noise level when using %s.signal_to_noise" %
                key)
        sn_target = galsim.config.ParseValue(base[key], 'signal_to_noise',
                                             base, float)[0]
        try:
            # In case noise variance is an image
            noise_var = noise_var.array.mean()
        except AttributeError:
            pass

        # Now determine what flux we need to get our desired S/N
        # There are lots of definitions of S/N, but here is the one used by Great08
        # We use a weighted integral of the flux:
        # S = sum W(x,y) I(x,y) / sum W(x,y)
        # N^2 = Var(S) = sum W(x,y)^2 Var(I(x,y)) / (sum W(x,y))^2
        # Now we assume that Var(I(x,y)) is dominated by the sky noise, so
        # Var(I(x,y)) = var
        # We also assume that we are using a matched filter for W, so W(x,y) = I(x,y).
        # Then a few things cancel and we find that
        # S/N = sqrt( sum I(x,y)^2 / var )

        sn_meas = math.sqrt(np.sum(image.array**2, dtype=float) / noise_var)
        # Now we rescale the flux to get our desired S/N
        scale_factor = sn_target / sn_meas
        return scale_factor
Esempio n. 8
0
def DrawPSFStamp(psf, config, base, bounds, offset, method, logger):
    """
    Draw an image using the given psf profile.

    @returns the resulting image.
    """
    if 'draw_method' in config:
        method = galsim.config.ParseValue(config, 'draw_method', base, str)[0]
        if method not in valid_draw_methods:
            raise galsim.GalSimConfigValueError("Invalid draw_method.", method,
                                                valid_draw_methods)
    else:
        method = 'auto'

    if 'flux' in config:
        flux = galsim.config.ParseValue(config, 'flux', base, float)[0]
        psf = psf.withFlux(flux)

    if method == 'phot':
        rng = galsim.config.GetRNG(config, base)
        n_photons = psf.flux
    else:
        rng = None
        n_photons = 0

    wcs = base['wcs'].local(base['image_pos'])
    im = galsim.ImageF(bounds, wcs=wcs)
    im = psf.drawImage(image=im,
                       offset=offset,
                       method=method,
                       rng=rng,
                       n_photons=n_photons)

    if 'signal_to_noise' in config:
        if 'flux' in config:
            raise galsim.GalSimConfigError(
                "Cannot specify both flux and signal_to_noise for psf output")
        if method == 'phot':
            raise galsim.GalSimConfigError(
                "signal_to_noise option not implemented for draw_method = phot"
            )

        if 'image' in base and 'noise' in base['image']:
            noise_var = galsim.config.CalculateNoiseVariance(base)
        else:
            raise galsim.GalSimConfigError(
                "Need to specify noise level when using psf.signal_to_noise")

        sn_target = galsim.config.ParseValue(config, 'signal_to_noise', base,
                                             float)[0]

        sn_meas = math.sqrt(np.sum(im.array**2, dtype=float) / noise_var)
        flux = sn_target / sn_meas
        im *= flux

    return im
Esempio n. 9
0
    def reject(self, config, base, prof, psf, image, logger):
        """Check to see if this object should be rejected.

        @param config       The configuration dict for the stamp field.
        @param base         The base configuration dict.
        @param prof         The profile that was drawn.
        @param psf          The psf that was used to build the profile.
        @param image        The postage stamp image.  No noise is on it yet at this point.
        @param logger       If given, a logger object to log progress.

        @returns whether to reject this object
        """
        # Early exit if no profile
        if prof is None:
            return False

        if 'reject' in config:
            if galsim.config.ParseValue(config, 'reject', base, bool)[0]:
                logger.info('obj %d: reject evaluated to True',base['obj_num'])
                return True
        if 'min_flux_frac' in config:
            if not isinstance(prof, galsim.GSObject):
                raise galsim.GalSimConfigError(
                    "Cannot apply min_flux_frac for stamp types that do not use "
                    "a single GSObject profile.")
            expected_flux = prof.flux
            measured_flux = np.sum(image.array, dtype=float)
            min_flux_frac = galsim.config.ParseValue(config, 'min_flux_frac', base, float)[0]
            logger.debug('obj %d: flux_frac = %f', base.get('obj_num',0),
                         measured_flux / expected_flux)
            if measured_flux < min_flux_frac * expected_flux:
                logger.warning('Object %d: Measured flux = %f < %s * %f.',
                               base['obj_num'], measured_flux, min_flux_frac, expected_flux)
                return True
        if 'min_snr' in config or 'max_snr' in config:
            if not isinstance(prof, galsim.GSObject):
                raise galsim.GalSimConfigError(
                    "Cannot apply min_snr for stamp types that do not use "
                    "a single GSObject profile.")
            var = galsim.config.CalculateNoiseVariance(base)
            sumsq = np.sum(image.array**2, dtype=float)
            snr = np.sqrt(sumsq / var)
            logger.debug('obj %d: snr = %f', base.get('obj_num',0), snr)
            if 'min_snr' in config:
                min_snr = galsim.config.ParseValue(config, 'min_snr', base, float)[0]
                if snr < min_snr:
                    logger.warning('Object %d: Measured snr = %f < %s.',
                                   base['obj_num'], snr, min_snr)
                    return True
            if 'max_snr' in config:
                max_snr = galsim.config.ParseValue(config, 'max_snr', base, float)[0]
                if snr > max_snr:
                    logger.warning('Object %d: Measured snr = %f > %s.',
                                   base['obj_num'], snr, max_snr)
                    return True
        return False
Esempio n. 10
0
    def buildProfile(self, config, base, psf, gsparams, logger):
        """
        Build the object to be drawn.

        For the first item in the ring, this is the same as Basic. It stores the galaxy object
        created on the first time.  Then for later stamps in the ring, it retrieves the stored
        first galaxy and just rotates it before convolving by the psf.

        @param config       The configuration dict for the stamp field.
        @param base         The base configuration dict.
        @param psf          The PSF, if any.  This may be None, in which case, no PSF is convolved.
        @param gsparams     A dict of kwargs to use for a GSParams.  More may be added to this
                            list by the galaxy object.
        @param logger       If given, a logger object to log progress.

        @returns the final profile
        """
        # These have all already been checked to exist in SetupRing.
        num = galsim.config.ParseValue(config, 'num', base, int)[0]
        index = galsim.config.ParseValue(config, 'index', base, int)[0]
        if index < 0 or index >= num:
            raise galsim.GalSimConfigError("index %d out of bounds for Ring" %
                                           index)

        if index % num == 0:
            # Then we are on the first item in the ring, so make it normally.
            gal = galsim.config.BuildGSObject(base,
                                              'gal',
                                              gsparams=gsparams,
                                              logger=logger)[0]
            if gal is None:
                raise galsim.GalSimConfigError(
                    "The gal field must define a valid galaxy for stamp type=Ring."
                )
            # Save the galaxy profile for next time.
            self.first = gal
        else:
            # Grab the saved first galaxy.
            if not hasattr(self, 'first'):
                raise galsim.GalSimConfigError(
                    "Building Ring after the first item, but no first gal stored."
                )
            gal = self.first
            full_rot = galsim.config.ParseValue(config, 'full_rotation', base,
                                                galsim.Angle)[0]
            dtheta = full_rot / num
            gal = gal.rotate(index * dtheta)

        # Apply any transformations that are given in the stamp field.
        gal = galsim.config.TransformObject(gal, config, base, logger)[0]

        if psf is not None:
            return galsim.Convolve(gal, psf)
        else:
            return gal
Esempio n. 11
0
def _BuildAdd(config, base, ignore, gsparams, logger):
    """Build a Sum object.
    """
    req = { 'items' : list }
    opt = { 'flux' : float }
    # Only Check, not Get.  We need to handle items a bit differently, since it's a list.
    galsim.config.CheckAllParams(config, req=req, opt=opt, ignore=ignore)

    gsobjects = []
    items = config['items']
    if not isinstance(items,list):
        raise galsim.GalSimConfigError("items entry for type=Add is not a list.")
    safe = True

    for i in range(len(items)):
        gsobject, safe1 = BuildGSObject(items, i, base, gsparams, logger)
        # Skip items with flux=0
        if 'flux' in items[i] and galsim.config.GetCurrentValue('flux',items[i],float,base) == 0.:
            logger.debug('obj %d: Not including component with flux == 0',base.get('obj_num',0))
            continue
        safe = safe and safe1
        gsobjects.append(gsobject)

    if len(gsobjects) == 0:
        raise galsim.GalSimConfigError("No valid items for type=Add")
    elif len(gsobjects) == 1:
        gsobject = gsobjects[0]
    else:
        # Special: if the last item in a Sum doesn't specify a flux, we scale it
        # to bring the total flux up to 1.
        if ('flux' not in items[-1]) and all('flux' in item for item in items[0:-1]):
            sum_flux = 0
            for item in items[0:-1]:
                sum_flux += galsim.config.GetCurrentValue('flux',item,float,base)
            f = 1. - sum_flux
            if (f < 0):
                logger.warning(
                    "Warning: Automatic flux for the last item in Sum (to make the total flux=1) "
                    "resulted in negative flux = %f for that item"%f)
            logger.debug('obj %d: Rescaling final object in sum to have flux = %f',
                         base.get('obj_num',0), f)
            gsobjects[-1] = gsobjects[-1].withFlux(f)
        if gsparams: gsparams = galsim.GSParams(**gsparams)
        else: gsparams = None
        gsobject = galsim.Add(gsobjects,gsparams=gsparams)

    if 'flux' in config:
        flux, safe1 = galsim.config.ParseValue(config, 'flux', base, float)
        logger.debug('obj %d: flux == %f',base.get('obj_num',0),flux)
        gsobject = gsobject.withFlux(flux)
        safe = safe and safe1

    return gsobject, safe
Esempio n. 12
0
def _GenerateFromFormattedStr(config, base, value_type):
    """@brief Create a string from a format string
    """
    req = {'format': str, 'items': list}
    # Ignore items for now, we'll deal with it differently.
    params, safe = GetAllParams(config, base, req=req)
    format = params['format']
    items = params['items']

    # Figure out what types we are expecting for the list elements:
    tokens = format.split('%')
    val_types = []
    skip = False
    for token in tokens[1:]:  # skip first one.
        # It we have set skip, then skip this one.
        if skip:
            skip = False
            continue
        # If token == '', then this is a %% in the original string.  Skip this and the next token.
        if len(token) == 0:
            skip = True
            continue
        token = token.lstrip(
            '0123456789lLh')  # ignore field size, and long/short specification
        if len(token) == 0:
            raise galsim.GalSimConfigError(
                "Unable to parse %r as a valid format string" % format)
        if token[0].lower() in 'diouxX':
            val_types.append(int)
        elif token[0].lower() in 'eEfFgG':
            val_types.append(float)
        elif token[0].lower() in 'rs':
            val_types.append(str)
        else:
            raise galsim.GalSimConfigError(
                "Unable to parse %r as a valid format string" % format)

    if len(val_types) != len(items):
        raise galsim.GalSimConfigError(
            "Number of items for FormatStr (%d) does not match number expected from "
            "format string (%d)" % (len(items), len(val_types)))
    vals = []
    for index in range(len(items)):
        val, safe1 = ParseValue(items, index, base, val_types[index])
        safe = safe and safe1
        vals.append(val)

    final_str = format % tuple(vals)
    #print(base['obj_num'],'FormattedStr = ',final_str)
    return final_str, safe
Esempio n. 13
0
    def setup(self, config, base, image_num, obj_num, ignore, logger):
        """Do the initialization and setup for building the image.

        This figures out the size that the image will be, but doesn't actually build it yet.

        @param config       The configuration dict for the image field.
        @param base         The base configuration dict.
        @param image_num    The current image number.
        @param obj_num      The first object number in the image.
        @param ignore       A list of parameters that are allowed to be in config that we can
                            ignore here. i.e. it won't be an error if these parameters are present.
        @param logger       If given, a logger object to log progress.

        @returns xsize, ysize
        """
        logger.debug('image %d: Building Scattered: image, obj = %d,%d',
                     image_num, image_num, obj_num)

        self.nobjects = self.getNObj(config, base, image_num)
        logger.debug('image %d: nobj = %d', image_num, self.nobjects)

        # These are allowed for Scattered, but we don't use them here.
        extra_ignore = [
            'image_pos', 'world_pos', 'stamp_size', 'stamp_xsize',
            'stamp_ysize', 'nobjects'
        ]
        opt = {'size': int, 'xsize': int, 'ysize': int}
        params = galsim.config.GetAllParams(config,
                                            base,
                                            opt=opt,
                                            ignore=ignore + extra_ignore)[0]

        size = params.get('size', 0)
        full_xsize = params.get('xsize', size)
        full_ysize = params.get('ysize', size)

        if (full_xsize <= 0) or (full_ysize <= 0):
            raise galsim.GalSimConfigError(
                "Both image.xsize and image.ysize need to be defined and > 0.")

        # If image_force_xsize and image_force_ysize were set in config, make sure it matches.
        if (('image_force_xsize' in base
             and full_xsize != base['image_force_xsize'])
                or ('image_force_ysize' in base
                    and full_ysize != base['image_force_ysize'])):
            raise galsim.GalSimConfigError(
                "Unable to reconcile required image xsize and ysize with provided "
                "xsize=%d, ysize=%d, " % (full_xsize, full_ysize))

        return full_xsize, full_ysize
Esempio n. 14
0
def _GenerateFromRandomDistribution(config, base, value_type):
    """@brief Return a random value drawn from a user-defined probability distribution
    """
    rng = galsim.config.GetRNG(config, base)

    ignore = [ 'x', 'f', 'x_log', 'f_log' ]
    opt = {'function' : str, 'interpolant' : str, 'npoints' : int,
           'x_min' : float, 'x_max' : float }
    kwargs, safe = galsim.config.GetAllParams(config, base, opt=opt, ignore=ignore)

    # Allow the user to give x,f instead of function to define a LookupTable.
    if 'x' in config or 'f' in config:
        if 'x' not in config or 'f' not in config:
            raise galsim.GalSimConfigError(
                "Both x and f must be provided for type=RandomDistribution")
        if 'function' in kwargs:
            raise galsim.GalSimConfigError(
                "Cannot provide function with x,f for type=RandomDistribution")
        x = config['x']
        f = config['f']
        x_log = config.get('x_log', False)
        f_log = config.get('f_log', False)
        interpolant = kwargs.pop('interpolant', 'spline')
        kwargs['function'] = galsim.LookupTable(x=x, f=f, x_log=x_log, f_log=f_log,
                                                interpolant=interpolant)
    else:
        if 'function' not in kwargs:
            raise galsim.GalSimConfigError(
                "function or x,f  must be provided for type=RandomDistribution")
        if 'x_log' in config or 'f_log' in config:
            raise galsim.GalSimConfigError(
                "x_log, f_log are invalid with function for type=RandomDistribution")

    if '_distdev' not in config or config['_distdev_kwargs'] != kwargs:
        # The overhead for making a DistDeviate is large enough that we'd rather not do it every
        # time, so first check if we've already made one:
        distdev=galsim.DistDeviate(rng,**kwargs)
        config['_distdev'] = distdev
        config['_distdev_kwargs'] = kwargs
    else:
        distdev = config['_distdev']

    # Typically, the rng will change between successive calls to this, so reset the
    # seed.  (The other internal calculations don't need to be redone unless the rest of the
    # kwargs have been changed.)
    distdev.reset(rng)

    val = distdev()
    #print(base['obj_num'],'distdev = ',val)
    return val, False
Esempio n. 15
0
def GetRNG(config, base, logger=None, tag=''):
    """Get the appropriate current rng according to whatever the current index_key is.

    If a logger is provided, then it will emit a warning if there is no current rng setup.

    Parameters:
        config:         The configuration dict for the current item being worked on.
        base:           The base configuration dict.
        logger:         If given, a logger object to log progress. [default: None]
        tag:            If given, an appropriate name for the current item to use in the
                        warning message. [default: '']

    Returns:
        either the appropriate rng for the current index_key or None
    """
    logger = LoggerWrapper(logger)
    index, index_key = GetIndex(config, base)
    logger.debug("GetRNG for %s: %s", index_key, index)

    rng_num = config.get('rng_num', 0)
    if rng_num != 0:
        if int(rng_num) != rng_num:
            raise galsim.GalSimConfigValueError("rng_num must be an integer",
                                                rng_num)
        rngs = base.get(index_key + '_rngs', None)
        if rngs is None:
            raise galsim.GalSimConfigError(
                "rng_num is only allowed when image.random_seed is a list")
        if rng_num < 0 or rng_num > len(rngs):
            raise galsim.GalSimConfigError(
                "rng_num is invalid.  Must be in [0,%d]" % (len(rngs)))
        rng = rngs[int(rng_num)]
    else:
        rng = base.get(index_key + '_rng', None)

    if rng is None:
        logger.debug("No index_key_rng.  Use base[rng]")
        rng = base.get('rng', None)

    if rng is None and logger:
        # Only report the warning the first time.
        rng_tag = tag + '_reported_no_rng'
        if rng_tag not in base:
            base[rng_tag] = True
            logger.warning(
                "No base['rng'] available for %s.  Using /dev/urandom.", tag)

    return rng
Esempio n. 16
0
    def buildProfile(self, config, base, psf, gsparams, logger):
        """Build the surface brightness profile (a GSObject) to be drawn.

        For the Basic stamp type, this builds a galaxy from the base['gal'] dict and convolves
        it with the psf (if given).  If either the psf or the galaxy is None, then the other one
        is returned as is.

        @param config       The configuration dict for the stamp field.
        @param base         The base configuration dict.
        @param psf          The PSF, if any.  This may be None, in which case, no PSF is convolved.
        @param gsparams     A dict of kwargs to use for a GSParams.  More may be added to this
                            list by the galaxy object.
        @param logger       If given, a logger object to log progress.

        @returns the final profile
        """
        gal = galsim.config.BuildGSObject(base, 'gal', gsparams=gsparams, logger=logger)[0]

        if psf:
            if gal:
                return galsim.Convolve(gal,psf)
            else:
                return psf
        else:
            if gal:
                return gal
            elif 'gal' in base or 'psf' in base:
                return None
            else:
                raise galsim.GalSimConfigError(
                    "At least one of gal or psf must be specified in config. "
                    "If you really don't want any object, use gal type = None.")
Esempio n. 17
0
    def whiten(self, prof, image, config, base, logger):
        """If appropriate, whiten the resulting image according to the requested noise profile
        and the amount of noise originally present in the profile.

        @param prof         The profile to draw.
        @param image        The image onto which to draw the profile.
        @param config       The configuration dict for the stamp field.
        @param base         The base configuration dict.
        @param logger       If given, a logger object to log progress.

        @returns the variance of the resulting whitened (or symmetrized) image.
        """
        # If the object has a noise attribute, then check if we need to do anything with it.
        current_var = 0.  # Default if not overwritten
        if isinstance(prof,galsim.GSObject) and prof.noise is not None:
            if 'image' in base and 'noise' in base['image']:
                noise = base['image']['noise']
                whiten = symmetrize = False
                if 'whiten' in noise:
                    whiten = galsim.config.ParseValue(noise, 'whiten', base, bool)[0]
                if 'symmetrize' in noise:
                    symmetrize = galsim.config.ParseValue(noise, 'symmetrize', base, int)[0]
                if whiten and symmetrize:
                    raise galsim.GalSimConfigError('Only one of whiten or symmetrize is allowed')
                if whiten or symmetrize:
                    # In case the galaxy was cached, update the rng
                    rng = galsim.config.GetRNG(noise, base, logger, "whiten")
                    prof.noise.rng.reset(rng)
                if whiten:
                    current_var = prof.noise.whitenImage(image)
                if symmetrize:
                    current_var = prof.noise.symmetrizeImage(image, symmetrize)
        return current_var
Esempio n. 18
0
def SetInConfig(config, key, value):
    """Set the value of a (possibly extended) key in a config dict.

    If key is a simple string, then this is equivalent to config[key] = value.
    However, key is allowed to be a chain of keys such as 'gal.items.0.ellip.e', in which
    case this function will set config['gal']['items'][0]['ellip']['e'] = value.

    Parameters:
        config:     The configuration dict.
        key:        The possibly extended key.

    Returns:
        the value of that key from the config.
    """
    d, k = ParseExtendedKey(config, key)
    if value == '':
        # This means remove it, if it is there.
        d.pop(k, None)
    else:
        try:
            d[k] = value
        except Exception as e:
            raise galsim.GalSimConfigError(
                "Unable to parse extended key %s.  Field %s is invalid." %
                (key, k))
Esempio n. 19
0
    def getNObj(self, config, base, image_num):
        """Get the number of objects that will be built for this image.

        Parameters:
            config:     The configuration dict for the image field.
            base:       The base configuration dict.
            image_num:  The current image number.

        Returns:
            the number of objects
        """
        orig_index_key = base.get('index_key',None)
        base['index_key'] = 'image_num'
        base['image_num'] = image_num

        # Allow nobjects to be automatic based on input catalog
        if 'nobjects' not in config:
            nobj = galsim.config.ProcessInputNObjects(base)
            if nobj is None:
                raise galsim.GalSimConfigError(
                    "Attribute nobjects is required for image.type = Scattered")
        else:
            nobj = galsim.config.ParseValue(config,'nobjects',base,int)[0]
        base['index_key'] = orig_index_key
        return nobj
Esempio n. 20
0
def GetInputObj(input_type, config, base, param_name):
    """Get the input object needed for generating a particular value

    @param input_type   The type of input object to get
    @param config       The config dict for this input item
    @param base         The base config dict
    @param param_name   The type of value that we are trying to construct (only used for
                        error messages).
    """
    if '_input_objs' not in base or input_type not in base['_input_objs']:
        raise galsim.GalSimConfigError("No input %s available for type = %s" %
                                       (input_type, param_name))

    if 'num' in config:
        num = galsim.config.ParseValue(config, 'num', base, int)[0]
    else:
        num = 0

    if num < 0:
        raise galsim.GalSimConfigValueError(
            "Invalid num < 0 supplied for %s." % param_name, num)
    if num >= len(base['_input_objs'][input_type]):
        raise galsim.GalSimConfigValueError(
            "Invalid num supplied for %s (too large)" % param_name, num)

    return base['_input_objs'][input_type][num]
Esempio n. 21
0
def ParseExtendedKey(config, key):
    """Traverse all but the last item in an extended key and return the resulting config, key.

    If key is an extended key like gal.items.0.ellip.e, then this will return the tuple.
    (config['gal']['items'][0]['ellip'], 'e').

    If key is a regular string, then is just returns the original (config, key).

    @param config       The configuration dict.
    @param key          The possibly extended key.

    @returns the equivalent (config, key) where key is now a regular non-extended key.
    """
    # This is basically identical to the code for Dict.get(key) in catalog.py.
    chain = key.split('.')
    while True:
        d = config
        k = chain.pop(0)
        try:
            k = int(k)
        except ValueError:
            pass
        if len(chain) == 0: break
        try:
            config = d[k]
        except (TypeError, KeyError):
            # TypeError for the case where d is a float or Position2D, so d[k] is invalid.
            # KeyError for the case where d is a dict, but k is not a valid key.
            raise galsim.GalSimConfigError(
                "Unable to parse extended key %s.  Field %s is invalid." %
                (key, k))
    return d, k
Esempio n. 22
0
    def getFilename(self, config, base, logger):
        """Get the file_name for the current file being worked on.

        Note that the base class defines a default extension = '.fits'.
        This can be overridden by subclasses by changing the default_ext property.

        @param config           The configuration dict for the output type.
        @param base             The base configuration dict.
        @param logger           If given, a logger object to log progress.

        @returns the filename to build.
        """
        if 'file_name' in config:
            SetDefaultExt(config['file_name'], self.default_ext)
            file_name = galsim.config.ParseValue(config, 'file_name', base,
                                                 str)[0]
        elif 'root' in base and self.default_ext is not None:
            # If a file_name isn't specified, we use the name of the config file + '.fits'
            file_name = base['root'] + self.default_ext
        else:
            raise galsim.GalSimConfigError(
                "No file_name specified and unable to generate it automatically."
            )

        # Prepend a dir to the beginning of the filename if requested.
        if 'dir' in config:
            dir = galsim.config.ParseValue(config, 'dir', base, str)[0]
            file_name = os.path.join(dir, file_name)

        ensure_dir(file_name)

        return file_name
Esempio n. 23
0
def CalculateNoiseVariance(config):
    """
    Calculate the noise variance from the noise specified in the noise dict.

    Parameters:
        config:     The configuration dict

    Returns:
        the noise variance
    """
    noise = config['image']['noise']
    if not isinstance(noise, dict):
        raise galsim.GalSimConfigError("image.noise is not a dict.")

    noise_type = noise.get('type', 'Poisson')
    if noise_type not in valid_noise_types:
        raise galsim.GalSimConfigValueError("Invalid noise.type.", noise_type,
                                            valid_noise_types)

    index, orig_index_key = galsim.config.GetIndex(noise, config)
    config['index_key'] = 'image_num'

    builder = valid_noise_types[noise_type]
    var = builder.getNoiseVariance(noise, config)
    config['index_key'] = orig_index_key

    return var
Esempio n. 24
0
    def addNoise(self, config, base, im, rng, current_var, draw_method,
                 logger):

        # Build the correlated noise
        cn = self.getCOSMOSNoise(config, base, rng)
        var = cn.getVariance()

        # Subtract off the current variance if any
        if current_var:
            logger.debug(
                'image %d, obj %d: Target variance is %f, current variance is %f',
                base.get('image_num', 0), base.get('obj_num', 0), var,
                current_var)
            if var < current_var:
                raise galsim.GalSimConfigError(
                    "Whitening already added more noise than the requested COSMOS noise."
                )
            cn -= galsim.UncorrelatedNoise(current_var, rng=rng, wcs=cn.wcs)

        # Add the noise to the image
        im.addNoise(cn)

        logger.debug(
            'image %d, obj %d: Added COSMOS correlated noise with variance = %f',
            base.get('image_num', 0), base.get('obj_num', 0), var)
        return var
Esempio n. 25
0
    def addNoise(self, config, base, im, rng, current_var, draw_method,
                 logger):

        # Read the noise variance
        var = self.getNoiseVariance(config, base)
        ret = var  # save for the return value

        # If we already have some variance in the image (from whitening), then we subtract this much
        # from sigma**2.
        if current_var:
            logger.debug(
                'image %d, obj %d: Target variance is %f, current variance is %f',
                base.get('image_num', 0), base.get('obj_num', 0), var,
                current_var)
            if var < current_var:
                raise galsim.GalSimConfigError(
                    "Whitening already added more noise than the requested Gaussian noise."
                )
            var -= current_var

        # Now apply the noise.
        import math
        sigma = math.sqrt(var)
        im.addNoise(galsim.GaussianNoise(rng, sigma=sigma))

        logger.debug('image %d, obj %d: Added Gaussian noise with var = %f',
                     base.get('image_num', 0), base.get('obj_num', 0), var)

        return ret
Esempio n. 26
0
def AddNoiseVariance(config, im, include_obj_var=False, logger=None):
    """
    Add the noise variance to an image according to the noise specifications in the noise dict.
    Typically, this is used for building a weight map, which is typically the inverse variance.

    @param config           The configuration dict
    @param im               The image onto which to add the variance values
    @param include_obj_var  Whether to add the variance from the object photons for noise
                            models that have a component based on the number of photons.
                            Note: if this is True, the returned variance will not include this
                            contribution to the noise variance.  [default: False]
    @param logger           If given, a logger object to log progress. [default: None]

    @returns the variance in the image
    """
    logger = galsim.config.LoggerWrapper(logger)
    if 'noise' in config['image']:
        noise = config['image']['noise']
    else:  # No noise.
        return
    if not isinstance(noise, dict):
        raise galsim.GalSimConfigError("image.noise is not a dict.")

    noise_type = noise.get('type', 'Poisson')
    if noise_type not in valid_noise_types:
        raise galsim.GalSimConfigValueError("Invalid noise.type.", noise_type,
                                            valid_noise_types)

    index, orig_index_key = galsim.config.GetIndex(noise, config)
    config['index_key'] = 'image_num'

    builder = valid_noise_types[noise_type]
    builder.addNoiseVariance(noise, config, im, include_obj_var, logger)
    config['index_key'] = orig_index_key
Esempio n. 27
0
    def buildWCS(self, config, base, logger):
        req = {'items': list}
        opt = {'index': int}
        # Only Check, not Get.  We need to handle items a bit differently, since it's a list.
        galsim.config.CheckAllParams(config, req=req, opt=opt)
        items = config['items']
        if not isinstance(items, list):
            raise galsim.GalSimConfigError(
                "items entry for type=List is not a list.")

        # Setup the indexing sequence if it hasn't been specified using the length of items.
        galsim.config.SetDefaultIndex(config, len(items))
        index, safe = galsim.config.ParseValue(config, 'index', base, int)

        if index < 0 or index >= len(items):
            raise galsim.GalSimConfigError(
                "index %d out of bounds for wcs type=List" % index)
        return BuildWCS(items, index, base)
Esempio n. 28
0
def test_galsim_config_error():
    """Test basic usage of GalSimConfigError
    """
    err = galsim.GalSimConfigError("Test")
    print('str = ', str(err))
    print('repr = ', repr(err))
    assert str(err) == "Test"
    assert isinstance(err, galsim.GalSimError)
    assert isinstance(err, ValueError)
    do_pickle(err)
Esempio n. 29
0
def _GetAngleValue(param):
    """ @brief Convert a string consisting of a value and an angle unit into an Angle.
    """
    try :
        value, unit = param.rsplit(None,1)
        value = float(value)
        unit = galsim.AngleUnit.from_name(unit)
        return galsim.Angle(value, unit)
    except (ValueError, TypeError, AttributeError) as e:
        raise galsim.GalSimConfigError("Unable to parse %s as an Angle. Caught %s"%(param,e))
Esempio n. 30
0
def _GenerateFromSequence(config, base, value_type):
    """@brief Return next in a sequence of integers
    """
    ignore = [ 'default' ]
    opt = { 'first' : value_type, 'last' : value_type, 'step' : value_type,
            'repeat' : int, 'nitems' : int, 'index_key' : str }
    kwargs, safe = GetAllParams(config, base, opt=opt, ignore=ignore)

    step = kwargs.get('step',1)
    first = kwargs.get('first',0)
    repeat = kwargs.get('repeat',1)
    last = kwargs.get('last',None)
    nitems = kwargs.get('nitems',None)

    if repeat <= 0:
        raise galsim.GalSimConfigValueError(
            "Invalid repeat for type = Sequence (must be > 0)", repeat)
    if last is not None and nitems is not None:
        raise galsim.GalSimConfigError(
            "At most one of the attributes last and nitems is allowed for type = Sequence")

    index, index_key = galsim.config.GetIndex(kwargs, base, is_sequence=True)
    #print('in GenFromSequence: index = ',index,index_key)

    if value_type is bool:
        # Then there are only really two valid sequences: Either 010101... or 101010...
        # Aside from the repeat value of course.
        if first:
            first = 1
            step = -1
            nitems = 2
        else:
            first = 0
            step = 1
            nitems = 2

    elif value_type is float:
        if last is not None:
            nitems = int( (last-first)/step + 0.5 ) + 1
    else:
        if last is not None:
            nitems = (last - first)//step + 1
    #print('nitems = ',nitems)
    #print('repeat = ',repeat)

    index = index // repeat
    #print('index => ',index)

    if nitems is not None and nitems > 0:
        index = index % nitems
        #print('index => ',index)

    value = first + index*step
    #print(base[index_key],'Sequence index = %s + %d*%s = %s'%(first,index,step,value))
    return value, False