castor_etc.photometry

Photometry

castor_etc.photometry provides classes for photometric calculations.

Module Contents

Classes

Photometry

Photometry class.

Data

_OPTIMAL_APER_FACTOR

_SUPERSAMPLE_FACTOR

API

castor_etc.photometry._OPTIMAL_APER_FACTOR = 1.4
castor_etc.photometry._SUPERSAMPLE_FACTOR = 20
class castor_etc.photometry.Photometry(TelescopeObj, SourceObj, BackgroundObj)

Photometry class.

Initialization

Initialize class for photometry calculations.

Note that the Source object (i.e., the SourceObj parameter) should have its spectrum in units of flam (erg/s/cm^2/A).

Parameters

TelescopeObj :: castor_etc.Telescope object The castor_etc.Telescope object containing the telescope parameters.

SourceObj :: castor_etc.Source object The castor_etc.Source object contaning the target source parameters. The source’s spectrum must be in units of photlam (photon/s/cm^2/A).

BackgroundObj :: castor_etc.Background object The castor_etc.Background object containing the background parameters. Dictionary keys must match the TelescopeObj.passbands keys.

Attributes

TelescopeObj :: castor_etc.Telescope object The castor_etc.Telescope object containing the telescope parameters.

SourceObj :: castor_etc.Source object The castor_etc.Source object contaning the target source parameters.

BackgroundObj :: castor_etc.Background object The castor_etc.Background object containing the background parameters.

Returns

Photometry instance

copy()

Convenience method for creating a deep copy of the Photometry object.

Parameters

None

Returns

Photometry_copy :: Photometry object The deep copy of the Photometry object.

_assign_exact_npix()

Internal function. Calculate the exact number of pixels in the aperture based on user parameters. Will compare this value to photutils’ number of pixels.

Parameters

None

Attributes


_exact_npix :: float The exact number of pixels in the aperture calculated from user parameters.

Returns

None

_create_aper_arrs(half_x, half_y, center, overwrite=False)

Parameters

half_x, half_y :: floats The half-widths (in arcsec) of the aperture in the x- and y-directions, respectively. (e.g., semimajor/semiminor axes, half of a rectangle’s length/width, etc.)

center :: 2-element 1D array of floats The (x, y) center of the aperture relative to the center of the source in arcsec. Positive values means the source is displaced to the bottom/left relative to the aperture center. This is because the source will always be at (0, 0) and the aperture center will be at this center value.

overwrite :: bool If True, allow overwriting of any existing aperture arrays.

Attributes

_xdim, _ydim :: ints The true, non-supersampled number of pixels along the x- and y-directions. This should be the dimensions of the final arrays after binning.

_aper_xs :: (M x N) 2D array of floats The aperture array containing the x-coordinates (in arcsec) relative to the center of the aperture. Includes supersampling.

_aper_ys :: (M x N) 2D array of floats The aperture array containing the y-coordinates (in arcsec) relative to the center of the aperture. Includes supersampling.

_aper_extent :: 4-element 1D list of floats The [xmin, xmax, ymin, ymax] extent of the aperture in arcsec (for plotting the weight arrays). Includes supersampling.

sky_background_weights :: (M x N) 2D array of floats The pixel weights for the sky background (incl. Earthshine, zodiacal light, geocoronal emission). This is currently all ones (1) (i.e., uniform noise). Includes supersampling. The sky background noise is given per sq. arcsec, so a 1 sq. arcsec pixel with a sky background weight of 1 means the pixel receives the full sky background noise (for that pixel), while a sky background weight of 0.4 means the pixel only receives 40% of the full sky background noise for that pixel.

dark_current_weights :: (M x N) 2D array of floats The pixel weights for the dark current. This is currently all ones (1) (i.e., uniform noise). Includes supersampling. A dark current weight of 1 means the pixel experiences the full dark current rate (per pixel), while a dark current weight of 0.4 means the dark current noise for that pixel is 40% of the telescope’s dark current value.

Returns

center_px :: 2-element 1D list of floats The (x, y) center index of the aperture coordinates arrays (i.e., _aper_xs and _aper_ys). To be very explicit, this is not (0, 0) but rather the center of the 2D arrays.

_calc_source_weights(center)

Calculate the source weights (before PSF convolution) for the given profile.

Parameters

center :: 2-element 1D array of floats The (x, y) center of the aperture relative to the center of the source in arcsec. Positive values means the source is displaced to the bottom/left relative to the aperture center. This is because the source will always be at (0, 0) and the aperture center will be at this center value.

Returns

source_weights :: (M x N) 2D array of floats The source weights for each pixel in the aperture. These (currently) represent the flux of the source at each pixel relative to the flux at the center of the source. After convolution & normalization, the source weights will represent the fraction of the source’s flux contained within the pixel.

show_source_weights(passband, mark_source=False, source_markersize=4, norm=None, plot=True)

Plot the source as seen through the photometry aperture. The pixels are colored by the fraction of the source’s flux contained within each pixel. Coloring also includes the effects of fractional pixel weights (i.e., from the aperture mask, visualized using show_aper_weights()). These two effects combined give the “source weights”.

Changing the source weights will affect the fraction of flux contained within the aperture and thus affect photometry calculations.

Parameters

passband :: “noiseless” or one of the TelescopeObj.passbands keys If “noiseless”, then the source weights are shown without any point spread function (PSF) convolution. If one of the TelescopeObj.passbands keys, then the source weights are shown after convolution with the passband’s PSF. (Technically, these source weights are binned down from the supersampled version used for convolution with PSFs. That is, the true “noiseless” image is binned down from the PSF’s oversampled resolution to produce this “noiseless” image.)

mark_source :: bool If True, mark the center of the source with a cyan dot.

source_markersize :: int or float The markersize for the cyan point indicating the center of the source.

norm :: matplotlib.colors normalization class (e.g., LogNorm) or None The scaling and normalization to use for the colorbar. If None, then a linear scaling with the default (min pixel value, max pixel value) bounds are used.

plot :: bool If True, plot the source weights and return None. If False, return the figure, axis, image, and colorbar instance associated with the plot.

Returns

If plot is True: None

If plot is False: fig, ax :: matplotlib.figure.Figure and matplotlib.axes.Axes objects The figure and axis instance associated with the plot.

img :: matplotlib.image.AxesImage object The image instance returned by ax.imshow.

cbar :: matplotlib.colorbar.Colorbar object The colorbar instance associated with the plot.

show_aper_weights(plot=True)

Plot the aperture photometry mask. The aperture mask shows the fractional overlap between the aperture and the pixel, ranging from (0, 1]. A pixel that is wholly contained in the aperture has an aperture weight equal to 1. Similarly, a pixel that is partially contained in the aperture has a weight between 0 and 1 (exclusive) directly proportional to the area of the aperture that overlaps the pixel. A pixel that is wholly outside the aperture is assigned a weight of NaN.

The “effective number of aperture pixels” is the sum of these pixel values (excluding all NaNs). This approach using fractional pixel weights gives a more accurate pixel count for non-rectangular aperture shapes while maintaning the benefit of allowing pixel-by-pixel modifications, if desired. This is to emulate the physical process of reading out and summing up each pixel in the aperture.

Parameters

plot :: bool If True, plot the aperture weights and return None. If False, return the figure, axis, image, and colorbar instance associated with the plot.

Returns

If plot is True: None

If plot is False: fig, ax :: matplotlib.figure.Figure and matplotlib.axes.Axes objects The figure and axis instance associated with the plot.

img :: matplotlib.image.AxesImage object The image instance returned by ax.imshow.

cbar :: matplotlib.colorbar.Colorbar object The colorbar instance associated with the plot.

set_background_weights(sky_background_weights)

Set the pixel weights for the sky background. The value of these weights represent the amount of sky background noise at each pixel. By default, the sky background weights are uniform (i.e., equal to 1.0) over the aperture (except at the aperture edges, where there may be fractional pixel weighting as described in the show_aper_weights() docstring).

When doing photometry calculations, these sky background weights will be multiplied with the calculated sky background noise per pixel (includes Earthshine, zodiacal light, and geocoronal emission) and summed pixel-by-pixel to determine the total background noise contribution; any pixels with a value of NaN are excluded from the summation.

No restrictions are placed on the value of the sky background weights, but the user is responsible for ensuring they make sense in the relevant context. For example, if one pixel in the aperture has double the sky background noise while the rest of the pixels have ordinary levels of background noise, the user should set that one pixel to have a background weight of 2.0 and keep the other background weights at 1.0 (as opposed to setting that one pixel weight to 1.0 while changing the other weights to 0.5). As a reminder, this is because the total sky background noise is based on multiplying the sky background noise per pixel by these background weights—the latter scenario would decrease the total sky background noise as opposed to slightly increasing it…

Parameters

sky_background_weights :: (M x N) 2D array of floats The pixel weights for the sky background (incl. Earthshine, zodiacal light, geocoronal emission). The shape must match the shape of the aperture array (see the source_weights attribute). The sky background noise is given per sq. arcsec, so a 1 sq. arcsec pixel with a sky background weight of 1 means the pixel receives the full sky background noise (for that pixel), while a sky background weight of 0.4 means the pixel only receives 40% of the full sky background noise for that pixel.

Attributes

sky_background_weights :: (M x N) 2D array of floats The pixel weights for the sky background. Note that the sky background includes Earthshine, zodiacal light, and geocoronal emission.

Returns

None

set_dark_current_weights(dark_current_weights)

Set the pixel weights for the dark current. The value of these weights represent the amount of dark current noise at each pixel. By default, the dark current weights are uniform (i.e., equal to 1.0) over the aperture (except at the aperture edges, where there may be fractional pixel weighting as described in the show_aper_weights() docstring).

When doing photometry calculations, these dark current weights will be multiplied with the dark current value per pixel (specified in the Telescope object) and summed pixel-by-pixel to determine the total dark current contribution; any pixels with a value of NaN are excluded from the summation.

No restrictions are placed on the value of the dark current weights, but the user is responsible for ensuring they make sense in the relevant context. For example, if one pixel in the aperture has double the dark current while the rest of the pixels have the nominal dark current, the user should set that one pixel to have a dark current weight of 2.0 and keep the other dark current weights at 1.0 (as opposed to setting that one pixel weight to 1.0 while changing the other weights to 0.5). As a reminder, this is because the total dark current noise is based on multiplying the dark current per pixel by these dark current weights—the latter scenario would decrease the total dark current noise as opposed to slightly increasing it…

Parameters

dark_current_weights :: (M x N) 2D array of floats The pixel weights for the dark current. The shape must match the shape of the aperture array (see source_weights attribute). A dark current weight of 1 means the pixel experiences the full dark current rate (per pixel), while a dark current weight of 0.4 means the dark current noise for that pixel is 40% of the telescope’s dark current value.

Attributes

dark_current_weights :: (M x N) 2D array of floats The pixel weights for the dark current.

_bin_arrs_remove_nans(center)

Bin arrays to self._xdim (N’) and self._ydim (M’), as well as calculate the effective number of pixels within the aperture. This method also removes columns and rows of the aperture mask containing all NaNs.

This method modifies the following attributes: _eff_npix, _aper_mask, source_weights, sky_background_weights, dark_current_weights, _aper_xs, _aper_ys. Also updates _aper_extent to reflect changed arrays.

Parameters

center :: 2-element 1D array of floats The (x, y) center of the aperture relative to the center of the source in arcsec. Positive values means the source is displaced to the bottom/left relative to the aperture center. This is because the source will always be at (0, 0) and the aperture center will be at this center value.

Attributes

_eff_npix :: float The effective number of pixels in the aperture.

_aper_mask :: (M’ x N’) 2D array of floats The aperture mask, including fractional pixel weights. The aperture mask shows the fractional overlap between the aperture and the pixel, ranging from (0, 1]. A pixel that is wholly contained in the aperture has an aperture weight equal to 1. Similarly, a pixel that is partially contained in the aperture has a weight between 0 and 1 (exclusive) directly proportional to the area of the aperture that overlaps the pixel. A pixel that is wholly outside the aperture has a weight of NaN. Now without rows and columns containing only NaNs.

source_weights :: dict of (M’ x N’) 2D array of floats The pixel weights for the source representing the fraction of flux contained in each pixel, including fractional pixel weights. Now without rows and columns containing only NaNs (based on _aper_mask).

sky_background_weights :: (M’ x N’) 2D array of floats The pixel weights for the sky background. Now without rows and columns containing only NaNs (based on _aper_mask).

dark_current_weights :: (M’ x N’) 2D array of floats The pixel weights for the dark current. Now without rows and columns containing only NaNs (based on _aper_mask).

_aper_xs :: (M’ x N’) 2D array of floats The aperture array containing the x-coordinates (in arcsec) relative to the center of the aperture. Now without rows and columns containing only NaNs (based on _aper_mask)

_aper_ys :: (M’ x N’) 2D array of floats The aperture array containing the y-coordinates (in arcsec) relative to the center of the aperture. Now without rows and columns containing only NaNs (based on _aper_mask)

_aper_extent :: 4-element 1D list of floats The [xmin, xmax, ymin, ymax] extent of the aperture in arcsec (for plotting the weight arrays). Updated to reflect the extent containing only rows and columns with at least 1 non-NaN value.

Returns

None

static _rotate_ab_to_xy(a, b, rotation, px_scale_arcsec)

Convert a (possibly rotated) source’s semimajor- and semiminor-axis dimensions to the x- and y- pixel dimensions needed for castor_etc.Photometry._create_aper_arrs().

Below is modified rotation matrix to ensure the full aperture is covered in subsequent arrays.

Parameters

a, b :: astropy.units.Quantity objects in units of arcsec The angular dimensions of the source’s semimajor and semiminor axis.

rotation :: float The CCW angle of the source with respect to the x-axis in radians.

px_scale_arcsec :: float The pixel scale in arcsec/pixel.

Returns

x, y :: floats The x- and y- pixel dimensions needed for castor_etc.Photometry._create_aper_arrs().

use_optimal_aperture(factor=_OPTIMAL_APER_FACTOR, quiet=False, overwrite=False)

Uses the “optimal” circular aperture calculated from the telescope PSF’s full-width at half-maximum (FWHM). Note that this aperture is only valid for point sources.

The default optimal aperture factor assumes the point spread function (PSF) is a 2D Gaussian (more specifically, a 2D multivariate Normal distribution) with the same FWHM as the telescope’s FWHM. The “true” optimal aperture differs between passbands since they all have different PSFs.

We estimate the fraction of flux contained within the aperture (i.e., the encircled energy) by supersampling the user’s aperture at the PSF’s (supersampled) resolution. We then compare the flux within the aperture to the total flux given by the sum of the PSF values. Note that the noiseless image (before PSF convolution) as well as the PSF array itself should both sum to roughly 1. The sum of the source_weights attribute for a particular passband gives the encircled energy within that passband.

Parameters

factor :: int or float The factor by which to scale the telescope’s FWHM. The radius of the optimal aperture will be R = factor * (FWHM/2).

quiet :: bool If False, print a warning if the point source’s diameter is larger than the telescope’s FWHM.

overwrite :: bool If True, allow overwriting of any existing aperture associated with this Photometry object.

Attributes

_aper_mask :: (M x N) 2D array of floats The aperture mask, including fractional pixel weights. The aperture mask shows the fractional overlap between the aperture and the pixel, ranging from (0, 1]. A pixel that is wholly contained in the aperture has an aperture weight equal to 1. Similarly, a pixel that is partially contained in the aperture has a weight between 0 and 1 (exclusive) directly proportional to the area of the aperture that overlaps the pixel. A pixel that is wholly outside the aperture has a weight of NaN.

source_weights :: dict of (M x N) 2D array of floats The pixel weights for the source for each of the telescope’s passbands, including fractional pixel weights. These weights represent the fraction of flux from the source contained in each pixel. A pixel with a source weight of 0.1 means that 10% of the flux from the source is contained within that pixel.

sky_background_weights :: (M x N) 2D array of floats The pixel weights for the sky background (incl. Earthshine, zodiacal light, geocoronal emission). The sky background noise is given per sq. arcsec, so a 1 sq. arcsec pixel with a sky background weight of 1 means the pixel receives the full sky background noise (for that pixel), while a sky background weight of 0.4 means the pixel only receives 40% of the full sky background noise for that pixel.

dark_current_weights :: (M x N) 2D array of floats The pixel weights for the dark current. A dark current weight of 1 means the pixel experiences the full dark current rate (per pixel), while a dark current weight of 0.4 means the dark current noise for that pixel is 40% of the telescope’s dark current value.

Returns

None

use_elliptical_aperture(a, b, center=[0, 0] << u.arcsec, rotation=0, quiet=False, overwrite=False)

Use an elliptical aperture.

The fraction of the source’s flux enclosed by the aperture is estimated by supersampling the specified aperture at the PSF’s supersampled resolution and comparing the enclosed flux to the flux from a sufficiently large aperture that is centered on the source. The sum of the source_weights attribute for a particular passband gives the fraction of flux enclosed within the aperture for that passband.

Parameters

a, b :: int or float or astropy.Quantity angle The angular length of the semimajor and semiminor axes of the aperture, respectively. If int or float, a/b is assumed to be in pixel units.

center :: 2-element astropy.Quantity angles array The (x, y) center of the aperture relative to the center of the source. Positive values means the source is displaced to the bottom/left relative to the aperture center. This is because the source will always be at (0, 0) and the aperture center will be at this center value.

rotation :: int or float The counter-clockwise rotation angle in degrees of the ellipse’s semimajor axis from the positive x-axis. If rotation is 0, the semimajor axis is along the x-axis and the semiminor axis is along the y-axis.

quiet :: bool If True, do not print a warning if the source is an ExtendedSource object.

overwrite :: bool If True, allow overwriting of any existing aperture associated with this Photometry object.

Attributes

_aper_mask :: (M x N) 2D array of floats The aperture mask, including fractional pixel weights. The aperture mask shows the fractional overlap between the aperture and the pixel, ranging from (0, 1]. A pixel that is wholly contained in the aperture has an aperture weight equal to 1. Similarly, a pixel that is partially contained in the aperture has a weight between 0 and 1 (exclusive) directly proportional to the area of the aperture that overlaps the pixel. A pixel that is wholly outside the aperture has a weight of NaN.

source_weights :: dict of (M x N) 2D array of floats The pixel weights for the source for each of the telescope’s passbands, including fractional pixel weights. These weights represent the fraction of flux from the source contained in each pixel. A pixel with a source weight of 0.1 means that 10% of the flux from the source is contained within that pixel.

sky_background_weights :: (M x N) 2D array of floats The pixel weights for the sky background (incl. Earthshine, zodiacal light, geocoronal emission). The sky background noise is given per sq. arcsec, so a 1 sq. arcsec pixel with a sky background weight of 1 means the pixel receives the full sky background noise (for that pixel), while a sky background weight of 0.4 means the pixel only receives 40% of the full sky background noise for that pixel.

dark_current_weights :: (M x N) 2D array of floats The pixel weights for the dark current. A dark current weight of 1 means the pixel experiences the full dark current rate (per pixel), while a dark current weight of 0.4 means the dark current noise for that pixel is 40% of the telescope’s dark current value.

Returns

None

use_rectangular_aperture(width, length, center=[0, 0] << u.arcsec, quiet=False, overwrite=False)

Use a rectangular aperture.

The fraction of the source’s flux enclosed by the aperture is estimated by supersampling the specified aperture at the PSF’s supersampled resolution and comparing the enclosed flux to the flux from a sufficiently large aperture that is centered on the source. The sum of the source_weights attribute for a particular passband gives the fraction of flux enclosed within the aperture for that passband.

Parameters

width, length :: int or float or astropy.Quantity angle The width (along the x-axis) and length (along the y-axis) of the rectangular aperture. If int or float, length/width is assumed to be in pixel units.

center :: 2-element astropy.Quantity angles array The (x, y) center of the aperture relative to the center of the source. Positive values means the source is displaced to the bottom/left relative to the aperture center. This is because the source will always be at (0, 0) and the aperture center will be at this center value.

quiet :: bool If True, do not print a warning if the source is an ExtendedSource object.

overwrite :: bool If True, allow overwriting of any existing aperture associated with this Photometry object.

Attributes

_aper_mask :: (M x N) 2D array of floats The aperture mask, including fractional pixel weights. The aperture mask shows the fractional overlap between the aperture and the pixel, ranging from (0, 1]. A pixel that is wholly contained in the aperture has an aperture weight equal to 1. Similarly, a pixel that is partially contained in the aperture has a weight between 0 and 1 (exclusive) directly proportional to the area of the aperture that overlaps the pixel. A pixel that is wholly outside the aperture has a weight of NaN.

source_weights :: dict of (M x N) 2D array of floats The pixel weights for the source for each of the telescope’s passbands, including fractional pixel weights. These weights represent the fraction of flux from the source contained in each pixel. A pixel with a source weight of 0.1 means that 10% of the flux from the source is contained within that pixel.

sky_background_weights :: (M x N) 2D array of floats The pixel weights for the sky background (incl. Earthshine, zodiacal light, geocoronal emission). The sky background noise is given per sq. arcsec, so a 1 sq. arcsec pixel with a sky background weight of 1 means the pixel receives the full sky background noise (for that pixel), while a sky background weight of 0.4 means the pixel only receives 40% of the full sky background noise for that pixel.

dark_current_weights :: (M x N) 2D array of floats The pixel weights for the dark current. A dark current weight of 1 means the pixel experiences the full dark current rate (per pixel), while a dark current weight of 0.4 means the dark current noise for that pixel is 40% of the telescope’s dark current value.

Returns

None

static _calc_snr_from_t(t, signal, totskynoise, darkcurrent, readnoise, read_npix, nread=1)

Calculate the signal-to-noise ratio (SNR) reached given an integration time.

The equation to calculate the SNR is:

            SNR = (Q*t) / sqrt(Q*t + N_pix*t*Other_Poisson + N_pix*N_read*Read^2)

where:

  • SNR is the signal-to-noise ratio

  • t is the integration time in seconds

  • Q is the total signal due to the source in electrons/s

  • N_pix is the number of pixels occupied by the source on the detector

  • Other_Poisson = (B_Earthshine + B_zodi + B_geocoronal + Darkcurrent) is the total Poisson noise due to the sky backgorund (Earthshine, zodiacal light, and geocoronal emission), and dark current in electrons/s (per pixel)

  • N_read is the number of detector readouts

  • Read is the detector read noise in electrons (per pixel) The equation above is based on the formula detailed here: https://hst-docs.stsci.edu/wfc3ihb/chapter-9-wfc3-exposure-time-calculation/9-6-estimating-exposure-times.

In practice, the calculation takes in 2D arrays for the source signal, sky background, and dark current. The factor of N_pix is already included for these arrays since they have fractional pixel weighting. Therefore, simply summing up these arrays (excluding NaNs) is enough to calculate the total contribution from that element without further multiplying by N_pix. The only exception is N_read and the read noise, which are scalars and must be multiplied by an integer number of pixels.

Parameters

t :: int or float The integration time in seconds.

signal :: (M x N) 2D array of scalars 2D array giving the signal of the source (in electron/s) for each pixel in the aperture. This should include fractional pixel weighting from the aperture mask.

totskynoise :: (M x N) 2D array of scalars 2D array giving the total background noise due to Earthshine + zodiacal light + geocoronal emission (if applicable) in electron/s for each pixel in the aperture. This should include fractional pixel weighting from the aperture mask.

darkcurrent :: (M x N) 2D array of scalars 2D array giving the detector dark current in electron/s for each pixel in the aperture. This should include fractional pixel weighting from the aperture mask.

readnoise :: int or float The detector read noise in electron (per pixel).

read_npix :: int The integer number of pixels in the aperture. Only used for multiplying with the read noise and number of detector readouts.

nread :: int The number of detector readouts.

Returns

snr :: float The SNR reached after t seconds.

static _calc_t_from_snr(snr, signal, totskynoise, darkcurrent, readnoise, read_npix, nread=1)

Calculate the time required to reach a given signal-to-noise ratio (SNR).

The theoretical equation to calculate the time required to reach a given SNR is:

            t = {
                SNR^2 * (Q + N_pix * Other_Poisson)
                + sqrt[
                    SNR^4 * (Q + N_pix * Other_Poisson)^2
                    + 4 * Q^2 * SNR^2 * N_pix * N_read * Read^2
                ]
            } / (2 * Q^2)

where:

  • SNR is the desired signal-to-noise ratio

  • t is the integration time in seconds

  • Q is the total signal due to the source in electrons/s

  • N_pix is the number of pixels occupied by the source on the detector

  • Other_Poisson = (B_Earthshine + B_zodi + B_geocoronal + Darkcurrent) is the total Poisson noise due to the sky backgorund (Earthshine, zodiacal light, and geocoronal emission), and dark current in electrons/s (per pixel)

  • N_read is the number of detector readouts

  • Read is the detector read noise in electrons (per pixel) Note that this is simply the quadratic formula applied to the generic SNR equation. Also, the equation above is based on the formula detailed here: https://hst-docs.stsci.edu/wfc3ihb/chapter-9-wfc3-exposure-time-calculation/9-6-estimating-exposure-times.

In practice, the calculation takes in 2D arrays for the source signal, sky background, and dark current. The factor of N_pix is already included for these arrays since they have fractional pixel weighting. Therefore, simply summing up these arrays (excluding NaNs) is enough to calculate the total contribution from that element without further multiplying by N_pix. The only exception is N_read and the read noise, which are scalars and must be multiplied by an integer number of pixels.

Parameters

snr :: int or float The target SNR.

signal :: (M x N) 2D array of scalars 2D array giving the signal of the source (in electron/s) for each pixel in the aperture. This should include fractional pixel weighting from the aperture mask.

totskynoise :: (M x N) 2D array of scalars 2D array giving the total background noise due to Earthshine + zodiacal light + geocoronal emission (if applicable) in electron/s for each pixel in the aperture. This should include fractional pixel weighting from the aperture mask.

darkcurrent :: (M x N) 2D array of scalars 2D array giving the detector dark current in electron/s for each pixel in the aperture. This should include fractional pixel weighting from the aperture mask.

readnoise :: int or float The detector read noise in electron (per pixel).

read_npix :: int The integer number of pixels in the aperture. Only used for multiplying with the read noise and number of detector readouts.

nread :: int The number of detector readouts.

Returns

t :: float The time required to reach the given SNR in seconds.

calc_snr_or_t(t=None, snr=None, reddening=0, npix=None, nread=1, quiet=False)

Calculate the signal-to-noise ratio (SNR) reached in a given time or the integration time (t) required to reach a given SNR.

Again, note that the Source object associated with the Photometry instance should have its spectrum in units of flam (erg/s/cm^2/A) unless it is a CustomSource object.

Note that, for CustomSource objects, the reddening parameter will be ignored since the CustomSource object’s surface brightness profile should already be in units of electron/s (given for each pixel). Additionally, the SNR/integration time calculation will only be performed for the passband corresponding to the CustomSource object’s surface brightness profile.

Parameters

t :: float Integration time in seconds.

snr :: float Desired signal-to-noise ratio.

reddening :: int or float The reddening (i.e., E(B-V) in AB mags) based on the pointing. This value will be multiplied with each of the telescope’s extinction coefficients to get the total extinction in each passband.

npix :: int or float or None The number of pixels occupied by the source to use for the noise calculations (i.e., affects sky background, dark current, and read noise). If None, use the automatically calculated “effective pixel” count. Note that the number of pixels used for the read noise will always be npix rounded up to the nearest integer. Finally, this value does not affect the total signal of the source—only the non-signal-derived noise values are affected (e.g., higher npix means higher total sky background, dark current, and read noise but not higher signal).

nread :: int Number of detector readouts.

quiet :: bool If True, do not print an info messages about the fraction of flux contained within the aperture and do not print an info message about ignoring the reddening parameter when using a CustomSource.

Returns

results :: dict If t is given, this is the SNR reached after t seconds. If snr is given, this is the time in seconds required to reach the given SNR. The results are given for each TelescopeObj passband or, if using a CustomSource, for the passband defined in the CustomSource object.