Models and Generators#

GalPRIME Models#

GalPRIME is primarily designed to work with Sersic models, of the form

\[I(r) = I_{R_e}\exp\left\{b_n\left[1 - \left(\frac{r}{R_e}\right)^{1/n}\right]\right\}\]

Where n is the Sersic index and sets the overall profile shape. For most galaxies, the Sersic index will lie between 0.5 and 5. Disk galaxies typically have incides of n=1, which returns the usual exponential profile. Elliptical galaxies typically have indices around n=4, which gives higher light buildup in the center and in the outskirts of the galaxy.

GalPRIME has a set of builtin models that will cover most typical usages of the code. However, a user can define their own model, but it will require some additional work to modify the simulation pipeline.

GalPRIME models (galprime.models.galaxies.GalaxyModel) are essentially wrappers for 2D Astropy models. These models are designed to be automatically generated using KDEs and therefore require a few additional bells and whistles.

Each model has a directory of defaults set by the user. If the user does not modify any paramters for the model, each model creation will use the default parameters instead. You can see what defaults exist by:

import galprime as gp
mod = gp.SingleSersicModel()
mod.defaults

Furthermore, in order for a given GalPRIME sim to work, the input catalogue is required to have all of the parameters specified under the defaults. Setting up a config file properly involves checking what parameters are requested by the model, and customizing the config["KEYS"] section of the config file accordingly. For example, with a Single Sersic model, the user might have the following config section:

[KEYS]
    MAG = i
    REFF = R_GIM2D
    N = SERSIC_N_GIM2D
    ELLIP = ELL_GIM2D

Built-In Models#

To change which model GalPRIME uses, the user must modify the config["MODEL"]["MODEL_TYPE"] = index parameter in the configuration file. These are the current builtin models and their respective indices:

  1. SingleSersicModel: 1

  2. BulgeDiskSersicModel: 2

  3. ExponentialDiskModel: 3

  4. EllipticalModel: 4

Single-Sersic Model#

The main model used in GalPRIME. It is a single instance of a Sersic model, requiring keys of magnitude, effecitve radius in pixels, arcseconds or kpc, Sersic index, and ellipticity, given by

\[\epsilon = 1 - \frac{b}{a}\]

where b and a are the semiminor and semimajor axies of a given isophotal ellipse.

Note

If the effective radius unit is given as kpc by specifying config["MODEL"]["REFF_UNIT"] = "kpc", note that a redshift must always be specified to convert the effective radius into units of pixels. It is preferable to make a version of the table with effective radii given in pixels.

Bulge-Disk Model#

The bulge-disk model is a combination of two Sersic models. It requires a slighlty different set of inputs which are shown below.

[KEYS]
    MAG = gg2d
    FBULGE = __B_T_g
    REFF_BULGE = Rd
    N_BULGE = nb
    REFF_DISK = Re
    ELLIP_DISK = ellip_d
    ELLIP_BULGE = ellip_b

These include the TOTAL magnitude and the bulge fraction (i.e. how much of the light belongs to to the bulge between 0 and 1). All other paramters should be explanatory. This setup is designed to work with catalogues such as the bulge-disk decomposition work found in Simard+2011. GalPRIME automatically determines the magnitudes of each component, and will add together two separate Sersic models with a shared position angle.

Exponential Disk and Elliptical Models#

These are Sersic models with a fixed Sersic index. N=1 for exponential disks, and N=4 for elliptical models. Thus, these parameters are not needed when using these models.

Building Your Own Model#

If the user wishes to build their own model, they are required to create a subclass of the galprime.models.galaxies.GalaxyModel class. The subclass then needs to modify the following details. For example, if we wanted to instantiate a Gaussian model, it could be done using the following setup:

import galprime as gp

def gen_gaussian(**kwargs):

    shape = kwargs.get("SHAPE", (101, 101))
    if not isinstance(shape, tuple):
        shape = (shape, shape)
    x_0 = kwargs.get("x_0", shape[0] / 2)
    y_0 = kwargs.get("y_0", shape[1] / 2)

    ellip = kwargs.get("ELLIP", 0.1)
    x_stddev = kwargs.get("STDDEV", 5)
    y_stddev = x_stddev * (1 - ellip)
    pa = kwargs.get("PA", 0)

    mod = Gaussian2D(amplitude=1, x_mean=kwargs.get("x_0", shape[0] / 2), y_mean=kwargs.get("y_0", shape[1] / 2),
                        x_stddev=x_stddev, y_stddev=y_stddev, theta=pa)
    ys, xs = np.mgrid[:shape[0], :shape[1]]
    z = mod(xs, ys)

    mag, m0 = kwargs.get("MAG", 22), kwargs.get("M0", 27)

    z *= gp.Ltot(mag, m0=m0) / np.sum(z)

    params = {
        "MAG": mag, "M0": m0,
        "STDDEV": mod.x_stddev.value,
        "ELLIP": ellip, "PA":  mod.theta.value,
        "X0": x_0,  "Y0": y_0,
        "SHAPE": shape,
    }

    return z, params

class GaussianVerifier(gp.ParamVerifier):

    def __init__(self):
        super().__init__()
        self.conditions = [
            self.mag_condition,
            self.stddev_condition,
            self.ellip_condition,
        ]

    def mag_condition(self, p):
        return p["MAG"] > 0

    def stddev_condition(self, p):
        return p["STDDEV"] > 0

    def ellip_condition(self, p):
        return 0 <= p["ELLIP"] <= 1

class GaussianModel(gp.GalaxyModel):

    def __init__(self):
        self.params = {}
        self.defaults = {
            "MAG": 20.0,
            "STDDEV": 5.0,
            "ELLIP": 0.0,
        }
        self.verifier = GaussianVerifier()

    def _generate(self, **params):
        mod, mod_params = gen_gaussian(**params)
        self.params.update(mod_params)
        return mod, mod_params

Here there are three things to consider. The first is the method gen_gaussian which actually invokes the Astropy model and handles all keyword arguments. The second class is a verifier class which will check if the input parameters are valid for model generation. This is especially helpful for parameters generated from a KDE, which can sometimes return unphysical parameter sets (ellipticity < 0, for example). The last class is the actual GaussianModel class, which defines the default parameters and invokes a unique method called _generate.

Generating Synthetic Images#