Skip to content

PSF photometry plans (2017‐2018)

Larry Bradley edited this page Jul 18, 2024 · 1 revision

Archive of plans from the "PSF Photometry Algorithms and Software Workshop" held at STScI October 3-4, 2017.

PSF Photometry Block Diagram Specification

The block diagram:

![block_diagram](https://github.com/user-attachments/assets/f2f61c46-9c41-42c0-970b-853e671a694f)

BlockClassName

[Link to code if it exists]

A single sentence summarizing this block.

A longer description. Can be multiple paragraphs. You can link to other things like photutils.background.

Parameters

first_parameter_name : ~astropy.table.Table
Description of first input
second_parameter_name : SomeOtherType
Description of second input (if any)

Returns

first_return : ~astropy.table.Table
Description of the first thing this block outputs.
second_return
Many blocks will only return one object, but if more things are returned they can be described here (e.g., in python this is first, second = some_function(...))

Methods

Not all blocks will have these, but if desired some blocks can have methods that let you do something other than just running the block. E.g:

some_block = BlockClassName()
output = some_block(input1, input2, ...)  # this is what is documented above
result = some_block.method_name(...)  #this is documented here

method_name

Description of method

Parameters
first_parameter : type
Description ...
second_parameter : type
Description ...
Returns
first_return : type
Description ...

Example Usage

An example of using the block should be provided. This needs to be after a :: in the rst and indented:

print("This is example code")

BackgroundEstimator

Existing code documented here -- while the __call__ function has no docstring, the calc_background function is the actual block API. This function is used significantly through photutils and is heavily used within the PSF fitting process, so the documentation is summarized again here.

Routine to estimate the background level of images and provide background subtraction. Can either be applied across an entire image or applied in a two-dimensional grid, at which point background estimation is applied at each grid location locally.

Base class from which all background estimators are defined. Further parameters may be specified by subclass estimators, such as the ModeEstimatorBackground in photutils which takes median_factor and mean_factor as additional variables.

Parameters

sigma_clip : ~astropy.stats.SigmaClip object or None
The object which defines the level of sigma clipping applied to the data. If None then no clipping is performed. Passed when creating the class in __init__.
data : array_like or ~numpy.ma.MaskedArray
The array for which to calculate the background value. Passed to the __call__ function.
axis : int or None, optional
The array axis along which the background is calculated. If None, then the entire array is used. Passed to the __call__ function.

Returns

result : float or ~numpy.ma.MaskedArray
The calculated background value. If axis is None then a scalar will be returned, otherwise a ~numpy.ma.MaskedArray will be returned.

Methods

This block requires no methods beyond first initialisation, and __call__().

Example Usage

A variety of implementations of this block already exist in photutils. A canonical example is the mode estimation algorithm 3 * median - 2 * mean. This can be done on an array called image_data by using the block like so:

from photutils.background import ModeEstimatorBackground
bkg_estimator = ModeEstimatorBackground()
bkg_value = bkg_estimator(image_data)

The median/mean parameter values can be adjusted as keyword arguments to the estimator object if desired:

tweaked_bkg_estimator = ModeEstimatorBackground(median_factor=3.2, mean_factor=1.8)
new_bkg_value = tweaked_bkg_estimator(image_data)

The estimator will also accept a sigma clipping object that automatically does sigma clipping before the background is subtracted, like so:

from astropy.stats import SigmaClip
clipped_bkg_estimator = ModeEstimatorBackground(sigma_clip=SigmaClip(sigma=3.))
clipped_bkg_value = clipped_bkg_estimator(image_data)

CullerAndEnder

CullerAndEnder determines the fit quality of any sources found in PSF fitting routines that build off ~photutils.psf.BasicPSFPhotometry to include an iterative element, such as ~photutils.psf.IterativelySubtractedPSFPhotometry. It removes any sources from the input ~astropy.table.Table below a minimum fit criterion, and subsequently determines whether the loop can be ended prematurely, most likely when all found sources are of good quality and no additional sources have been found. This method may be subject to API changes in future versions and should not be considered final.

This block is an extra step at the end of each iterative PSF fitting loop, set up to consider whether the fitting process is complete, or if any sources can have their fits improved or be added to the output table. As such it requires three inputs: data, the ~astropy.table.Table of sources found in the N-1 previous iterations of the routine with their corresponding positions, fluxes, etc.; psf_model, the ~astropy.modeling.Fittable2DModel describing the PSF; and new_sources, a ~astropy.table.Table list of those sources found in the residual image once the data sources are removed (i.e., additional sources with no previously derived parameters).

The two halves of the block are further split into "cull" and "end": one function determining whether any sources in data are sufficiently poorly explained by psf_model that they should not be considered sources at all (e.g., they are cosmic ray hits picked up as being above some local background); and a second function, which considers whether we have reached the end of the finding of new sources prematurely (whether finding all sources before the loop counter reaches niters or simply because there are no new sources if niters = None). These functions (cull_data and end_loop) return a new_data table, with culled sources (those whose goodness-of-fit criteria are sufficiently low to be deemed non-stellar, e.g.), and end_flag, a boolean for whether the iterations can be ceased (prematurely or not), respectively.

Each subclass of CullerAndEnderBase can then provide its own definitions of cull_data and end_loop depending on the specific user cases. For example, end_loop could simply be return len(new_sources) == 0, while cull_data would likely involve the removal of sources with a chi-squared fit to psf_model above some threshold, or equivalent.

Parameters

data : ~astropy.table.Table
Table containing the sources.
psf_model : astropy.modeling.Fittable2DModel instance
PSF/PRF model to which the data are being fit.
new_sources : ~astropy.table.Table
Newly found list of sources to compare with the sources in data, when deciding whether to end iteration.

Returns

culled_data : ~astropy.table.Table
data with poor fits removed.
end_flag : boolean
Flag indicating whether to end iterative PSF fitting before the maximum number of loops.

Example Usage

In the simplest example, a list of sources found_sources with parameters x_0, y_0 and flux are compared to the expected PSF model (a ~astropy.modeling.Fittable2DModel such as photutils.psf.IntegratedGaussianPRF) and any fits above some minimum goodness-of-fit criterion are removed. If len(new_sources) == 0 then end_flag would return True, otherwise it will be set to False.:

from photutils.psf import CullerAndEnder
culler_and_ender = CullerAndEnder()
good_sources, end_flag = culler_and_ender(found_sources, psf_model, new_sources)

ObjectFinder

Existing code documented here -- see the find_stars function for the basic API. Finder is a relatively independent routine in the PSF fitting process, and as such it is documented within its own documentation blocks, based on StarFinderBase; it is documented here for completeness.

The object which defines the detection of objects in an image. Subclass finders may require additional parameters -- see below for the example of DAOStarFinder. The class is defined entirely by its find_stars function, with some initialization, depending on the individual subclass.

find_stars accepts data, the two-dimensional image in which sources should be found, and returns table, an ~astropy.table.Table list of sources which passed the given detection criteria. For example, in ~photutils.detection.DAOStarFinder a source must have given sharpness and roundness within specified ranges for acceptance as a detected source.

Parameters

data : array_like
The 2D image array in which the finder should detection sources.

Returns

table : ~astropy.table.Table
The table of detected sources.

Example Usage

StarFinder currently implements two methods: DAOFind and IRAFFind. For example, daofind can be run to find objects with FWHM of approximately 3 pixels with a peak 5-sigma above the background:

from photutils import DAOStarFinder
daofind = DAOStarFinder(fwhm=3.0, threshold=5.*std)
sources = daofind(data)

Fitter

The fitter block is unique in that it is a class not implemented as part of photutils. Rather, it is an object that follows the interface for fitters in the astropy.modeling package. Note that implicitly the fitters for PSF photometry are always fitters appropriate for 2D models (i.e., 2 input dimensions for the x and y pixel coordinates and a "flux" output).

GroupMaker

Documented as the __call__ method of GroupStarsBase -- see here for more information. The API for the group maker may be subject to change if group_stars requires changes to accommodate future revisions to the PSF fitting process -- primarily it would require updates if the PSF fitting is extended to include non-point sources and "scene maker" functionality. These large changes would subsequently require significant changes to the PSF fitting routines (e.g., ~photutils.psf.IterativelySubtractedPSFPhotometry) as a whole.

A function which groups stars within some critical separation, returning potentially overlapping sources with an additional column indicating their common group members. Subclasses of GroupStarsBase may require further input parameters, such as crit_separation required for DAOGroup.

The main functionality of this routine is within group_stars, which accepts starlist, a ~astropy.table.Table of sources with centroid positions, and returns group_starlist, the same ~astropy.table.Table passed to the routine but with an additional column indicating the group number of the sources. These sources are grouped by the individual criteria specified within the group_stars function defined by the GroupStarsBase subclass in question.

Parameters

starlist : ~astropy.table.Table
List of star positions; x_0 and y_0, the centroids of the sources, must be provided.

Returns

group_starlist : ~astropy.table.Table
starlist with an additional column appended -- group_id gives unique group number of mutually overlapping sources.

Methods

find_group

Convenience function provided by DAOGroup returning all objects within crit_separation from a given star from starlist.

Parameters
star : ~astropy.table.Row
Single star from starlist whose mutual group members are required.
starlist : ~astropy.table.Table
List of star positions; x_0 and y_0, the centroids of the sources, must be provided.
Returns

~numpy.array with the IDs of all stars with distance less than crit_separation to star.

Example Usage

Here we create a DAOGroup list of overlapping sources, then find all sources within 3 pixels of the first source in the list.

from photutils.psf.groupstars import DAOGroup
group = DAOGroup(starlist, crit_separation=3)
stargroups = group.group_stars(starlist)
id_overlap = group.find_stars(starlist[0], starlist)

NoiseData

NoiseData handles the determination and use of data uncertainty in the fitting of PSF models to image arrays, either by calculating the uncertainty of each image array value or by allowing the passing of a previously determined uncertainty array along with the array containing the image counts. This method may be subject to API changes and should not currently be considered the final API specification.

NoiseData is currently handled as an additional input parameter for ~photutils.psf.BasicPSFPhotometry, and by extension more complex PSF fitting routines, such as ~photutils.psf.IterativelySubtractedPSFPhotometry. It is either a function that calculates the corresponding uncertainty value of a given data value, a value such that the uncertainty array is ignored and all data values effectively given unity weighting, or set to indicate that the uncertainties for the image array were pre-computed and passed into the routine.

noise_calc should therefore be provided as a callable function (or None in which case it is ignored) returning the uncertainty (in standard deviations) of each pixel, the same shape as the input image array. The data and uncertainty arrays are then wrapped in an ~astropy.nddata.NDData instance. Alternatively, if image is provided as an ~astropy.nddata.NDData instance with both data and uncertainty attributes then noise_calc is ignored and the provided uncertainty array in image is used directly when calling the chosen fitter in the PSF fitting routine.

Parameters

image : array-like
The input image for which the uncertainty of each pixel is to be calculated.

Returns

uncertainty : array-like
The uncertainties of the input image values, as determined by the callable function noise_calc. Must return an array of the same shape as image.

Example Usage

The simplest, and perhaps most common, uncertainty used in photometry is that derived from Poissonian statistics, where the standard deviation is the square root of the photon counts. We can then simply pass the ~numpy.sqrt function as noise_calc:

import numpy as np
from astropy.modeling.fitting import LevMarLSQFitter

from photutils.psf import (DAOGroup, IntegratedGaussianPRF,
                           IterativelySubtractedPSFPhotometry)
from photutils.background import MMMBackground
from photutils.detection import IRAFStarFinder

daogroup = DAOGroup(crit_separation=8)
mmm_bkg = MMMBackground()
iraffind = IRAFStarFinder(threshold=2.5*self.mmm_bkg(image), fwhm=4.5)
fitter = LevMarLSQFitter()
psf_model = IntegratedGaussianPRF(sigma=2.05)
psf_model.sigma.fixed = False
iter_phot_psf = IterativelySubtractedPSFPhotometry(finder=iraffind,
                                                   group_maker=daogroup,
                                                   bkg_estimator=mmm_bkg,
                                                   psf_model=psf_model,
                                                   fitter=fitter,
                                                   fitshape=(11, 11),
                                                   niters=2,
                                                   noise_calc=np.sqrt)

However, if we wished, we could instead derive our own, more complex function to determine the corresponding uncertainty of a given pixel value. For instance, if -- for whatever reason -- the uncertainty of our data points was determined to be the logarithm of the absolute value of the counts, we could write such a function, remembering that the returned array must match in shape the input image:

def new_uncert_func(image):
    return np.log10(np.abs(image) + 5)
iter_phot_psf = IterativelySubtractedPSFPhotometry(finder=iraffind,
                                                   group_maker=daogroup,
                                                   bkg_estimator=mmm_bkg,
                                                   psf_model=psf_model,
                                                   fitter=fitter,
                                                   fitshape=(11, 11),
                                                   niters=2,
                                                   noise_calc=new_uncert_func)

PSFModel

The model for the PSF -- integrated over discrete pixels (see discussion on terminology for more details) -- on which we should evaluate the parameters of the source. The main input is a 2D image, with the model returning flux, x_0, and y_0, the overall source flux and centroid position. PSF models in the current photutils.psf are not explicitly defined as a specific class, but any 2D model (inputs: x,y, output: flux) can be considered a PSF Model.

This block is primarily an external block, defined as a ~astropy.modeling.Fittable2DModel, and should have a well documented subclass. The requirements for use within the PSF model block are that the ~astropy.modeling.Fittable2DModel have parameters flux, x_0, and y_0, as well as the evaluate function. When the model is combined with a minimization routine the best fitting flux and position for the input data image array containing the source are returned.

The ~photutils.psf.PRFAdapter class allows for the wrapping of any arbitrary other models to make it compatible with the machinery. Some individual models will require additional parameters, such as the IntegratedGaussianPRF which additionally requiring sigma as a parameter that describes the underlying Gaussian PSF.

Parameters

data : np.ndarray
Array containing the 2D image representing the source(s) that should be evaluated for centroiding and flux.

Returns

flux : float
The flux of the source; if any normalization has been applied then flux will be set to 1.
x_0 : float
The position of the source in the x axis, to sub-pixel resolution.
y_0 : float
The position of the source in the y axis, to sub-pixel resolution.

Methods

evaluate

Function that returns the values of the pixels of a model with flux, x_0 and y_0 as parameters.

Parameters
x : float
Central values of the pixels in the x axis at which to evaluate the PSF.
y : float
Central values of the pixels in the y axis at which to evaluate the PSF.
flux : float
Overall flux level of source, setting the scaling of each pixel.
x_0 : float
The centroid position of the source in the x axis.
y_0 : float
The centroid position of the source in the y axis.
Returns

The evaluation of the PSF, integrated over discrete pixels, at the centroid position and with the flux level specified.

Example Usage

Here we create a discrete Gaussian PSF with standard deviation of 2 pixels, and fit for centroid and overall flux level of a source.:

from photutils.psf import IntegratedGaussianPRF
psf_model = IntegratedGaussianPRF(sigma=2)
model_image = psf_model.evaluate(x, y, flux, x_0, y_0, sigma=2)

SceneMaker

SceneMaker does not yet exist in the framework of PSF Photometry. This API is therefore a work in progress and should be considered as such.

However, the block will likely involve an additional column or variable attributed to each source in the input ~astropy.table.Table indicating whether sources are stars or more extended objects. This column will be used in conjunction with SingleObjectModel, which already has the framework to accept object_type which allows for individual extended sources to be handled, depending on the specific class used for the specific purpose. The given list of single object models allowed by, and available to, SingleObjectModel must be the same list of physical source classes (stars, galaxies, etc.) as SceneMaker uses to group and merge detected sources into point sources or extended objects. The block must also handle the possibility of merging several point sources into an extended object and vice versa.

SceneMaker should be considered an extension of GroupMaker, and will likely accept outputs from that block. Sources grouped together by GroupMaker will subsequently be assigned as multiple single sources or one larger, extended source erroneously split up by the Finder, or some combination of the two. This information will then be used by SingleObjectModel to fit the grouped sources as either individual point sources or extended sources, based on object_type.

SingleObjectModel

SingleObjectModel handles the creation of the model image of an astrophysical object, combining physical on-sky flux distributions with the effects of the PSF, extending the psf_model block of the PSF fitting routine to include non-point sources. This method may be subject to API changes in future versions and should not be considered final.

This block is an additional step between the PSF (or PRF) ~astropy.modeling.Fittable2DModel and the ~astropy.modeling.fitting.Fitter instance, to allow for cases where the images being fit contain sources other than point sources. In these instances a combined PRF, combining the PSF resulting from telescope optics, CCD, etc. with that of the intrinsic source as it would appear with infinite resolution is required. If the source is a simple point source, then the block simply returns the given PSF, avoiding the lengthy computational time of image convolution.

The single object model -- the model determining what type of object (single star, binary star, galaxy, supernova, etc.) this source is assumed to be -- is described by an additional column of the star source list created during the PSF fitting routine. For a given fit the object is determined by star['object_type'] which is accepted as the string argument object_type by SingleObjectModel. Additionally, psf_model, the ~astropy.modeling.Fittable2DModel describing the PSF, accounting for quantized detector pixels, is required. The block then returns convolve_psf_model, the convolution of psf_model with the flux distribution intrinsic to the source with given internal parameters (such as galaxy distance to correct for apparent size, time since supernova explosion to produce the correct lightcurve, etc.). The class must be a subclass of SingleObjectModelBase, with the individual class provided to the PSF fitting routine accepting a specific set of sources to be passed in object_type, with each object being handled on a case-by-case basis.

This block is also related to SceneMaker, the future extension to the standard "source grouping" aspect of the PSF fitting process, which additionally allows for the grouping of several objects, otherwise assumed to be single point sources, into a composite extended source, and vice versa. It is SceneMaker which therefore dictates the object_type of a given source in the created star catalogue. SceneMaker must be set up such that it will group and merge star sources into groups such that all object types determined are accepted by SingleObjectModel -- the two blocks must therefore work closely in parallel with one another.

Parameters

psf_model : ~astropy.modeling.Fittable2DModel instance
The model describing the PSF/PRF of the image, used to fit individual point source objects.
object_type : string
The extended source type used to determine the innate light distribution of the source.

Returns

convolve_psf_model : ~astropy.modeling.Fittable2DModel instance
The new, combined PRF of the extended source, combining the intrinsic light distribution and PSF effects.

Example Usage

This class simply takes the ~astropy.modeling.Fittable2DModel instance and convolves it with the appropriate model describing the, e.g., galaxy light distribution:

from photutils.psf import SingleObjectModel
single_object_model = SingleObjectModel()
new_composite_psf = single_object_model(psf_to_add, star['object_type'])

PSF Fitting

The photutils.psf sub-package implements a variety of PSF fitting algorithms. These fitting algorithms are broken down into a series of modules, allowing the user to implement specific versions of each part of the fitting process, implementing a variety of fitting procedures best suited to the specific science cases. However, at its most basic, all choices share the same basic functionality: a 2D image is supplied and a ~astropy.table.Table of detected sources, with positions and flux counts, is returned. Optionally, the user can also supply a ~astropy.table.Table of previously detected source positions as an input, for cases such as forced photometry where sources have previously been found in an image and their positions known already.

This simplified workflow is expanded below for the case of the ~photutils.psf.IterativelySubtractedPSFPhotometry class, building upon the simpler ~photutils.psf.BasicPSFPhotometry algorithm. While there are additional blocks used within the workflow, the main ~photutils.psf.BasicPSFPhotometry flow is image -> finder -> group maker -> fitter -> sources. The extension to more complex fitting classes, such as ~photutils.psf.IterativelySubtractedPSFPhotometry, have the flow image -> finder -> group maker -> fitter -> culler and ender -> finder -> ... -> sources.

A brief summary of each block is given here, with context for how it fits into the overall PSF fitting framework, providing a top-down view of the process. More detailed descriptions of the blocks are available in other documentation pages (linked from each section below).

<img width="602" alt="graphviz_figure" src="https://github.com/user-attachments/assets/8bd1977f-b52b-4a74-a81c-7d9d34d55899">

(graphviz code)

digraph PSFFitting {
    compound = true;
    newrank = true;
    subgraph cluster0 {
        label="IterativePSFPhotometry"
        subgraph cluster2 {
            label="BasicPSFPhotometry"
            f [label = "finder"];
            g [label = "group maker"];
            some [label = "single object model"];
            n [label = "noise"];
            ft [label = "fitter"];
            b [label = "background estimator"];
            // required to allow finder and guess to combine into group maker
            invis [shape = circle, width = .1, fixedsize = true, style = invis];
        }
        c [label = "culler and ender"];
        im2 [label = "changes to image/sources inputs"];
    }

    w [label = "wcs"];
    i [label = "input image", shape = box];
    gs [label = "guess at sources", shape = box];
    p [label = "psf model"];
    sm [label = "scene maker"];
    st [label = "sources\n(astropy.table)", shape = box];

    label = <<FONT POINT-SIZE = "20"><I>photutils.psf</I>     class structures</FONT>>;
    labelloc = top;

    w -> i [style = dashed];
    // lhead = cluster0 sets the arrow end at the subgraph, rather than at finder itself
    i -> f;
    i -> b [style = dashed];
    gs -> invis [style = dashed];

    f -> g;
    f -> invis;
    invis -> g;
    some -> f [style = dashed];
    n -> ft;
    some -> ft;
    g -> ft;
    b -> f [style = dashed];
    b -> g [style = dashed];
    b -> ft [style = dashed];
    ft -> c [style = dashed];
    c -> im2 [style = dashed];
    im2 -> f [style = dashed];

    i -> gs [style = invis];

    p -> some;
    sm -> g [style = dotted];
    c -> st;
    // reverse arrow to put psf model above scene maker, saving space with scene
    // maker next to the middle of the main box
    p -> sm [style = dotted, dir = back];

    // puts things that should be at the top of the box at the top for orientation
    // and structuring; requires 'newrank' above to set subgraph items equal
    {rank = same; w; some;}
    {rank = same; p; f; n;}
    {rank = same; gs; g; sm;}
    {rank = same; c; st}

    subgraph cluster1 {
        ranksep=0
        label="Legend";
        solid [label = "Required flow of data", shape=plaintext];
        dashed [label = "Optional information flow", shape=plaintext];
        dotted [label = "Optional component", shape=plaintext];
        invis_1 [width = .1, fixedsize = true, style = invis];
        invis_2 [width = .1, fixedsize = true, style = invis];
        invis_3 [width = .1, fixedsize = true, style = invis];

    }
    solid -> invis_1 [style = solid];
    dashed -> invis_2 [style = dashed];
    dotted -> invis_3 [style = dotted];
    {rank = same; solid; invis_1; dashed; invis_2; dotted; invis_3;}

    im2 -> dashed [style = invis]
}

Input Image

The input image is the most fundamental part of the PSF fitting process, as it is the product on which all subsequent methodology is applied. The image must be a two-dimensional array of x and y coordinates with flux represented by array values. If a WCS -- contained within a FITS file, for instance -- is passed with the two-dimensional array then the position of sources can be given in sky coordinates, instead of pixel values. These, as well as arrays corresponding to the uncertainty of each data array value and a pixel-wise mask for data may be passed in an ~astropy.nddata.NDData object; alternatively, if they are passed separately an ~astropy.nddata.NDData object will be automatically converted. The given image's ~astropy.nddata.NDData is passed as an input to the chosen PSF fitting class.

Finder

The finder is the first step in the PSF fitting process, as sources must be discovered in the image before any kind of fit can be applied to them. All finders must be an implementation of ~photutils.detection.StarFinderBase; the finder must accept the input image and produce a ~astropy.table.Table of detected sources, by a set of criteria internal to the given Finder (see, e.g., ~photutils.detection.DAOStarFinder using roundness and sharpness to determine if sources are point-like). If an initial set of detected sources is passed to the fitter as init_guesses then Finder is not run on the first pass of an iterative fitting class, instead using the provided positions and fluxes. See the finder documentation for more details.

Group Maker

The second block to run in the fitting process, the various group maker processes, such as ~photutils.psf.DAOGroup, allow for the merging of sources that are astrometrically near to one another into a set of multiple sources. These sources must be fit simultaneously (see Fitter_) as a composite model, making deblending of sources possible. The block accepts the ~astropy.table.Table output from Finder and returns a second ~astropy.table.Table containing the same columns as the input as well as an additional column indicating the group number of each source. More information on this block can be found in Group Maker.

Fitter

Once a set of sources has been detected and grouped, each source must have its respective properties -- always position and flux, but potentially other properties -- determined. For this a Fitter instance is required; these are drawn from a separate class or instance of minimization routines, such as those implemented in ~astropy.modeling.fitting. The fitter has to accept the image -- or image cutout -- and a ~astropy.table.Table containing the initial guesses of source flux and position (and any additional derived parameters), and return an instance of the class with its parameters set to the best fit values. See below for more details on the PSF model, the fitter documentation for further information on the Fitter instance and its properties, and the Astropy documentation for information on the fitter API.

PSF Model

Perhaps the most important aspect of PSF fitting, the PSF Model describes the distribution of light falling on a given pixel from a source at some position with some total flux, fully describing the effects of telescope optics, quantized CCD pixels, etc. In this respect it is more properly described as a pixel response function (PRF) than a point spread function (PSF) -- see the PSF model documentation and PSF terminology pages for more details -- but we use a single term here for brevity. Similar to the Fitter, it is a separate callable class detailing a specific PSF response. This can be some analytical function, such as ~photutils.psf.IntegratedGaussianPRF, or an empirical description of the PSF, such as that implemented by the effective PSF functionality (see build-epsf details). These models must follow the Astropy modeling API for two-dimensional models; please refer there for more information.

Noise Description

The noise block within the PSF fitting process is, in much the same way as the Fitter block, a separate callable function mapping the relationship between the pixel values in the input image and the corresponding uncertainty of the pixel. It must therefore accept a two-dimensional array and return an array of the same shape as image. Alternatively it can be overloaded to indicate that the uncertainty array was passed along with image via an ~astropy.nddata.NDData instance. A more detailed description of this block is available in the noise data section.

Background Estimator

The image on which source extraction and evaluation is to be performed is not necessarily assumed to have had any pre-processing applied to it, and thus it may be necessary to account for the counts of the image background when handling PSF fitting. This block handles the determination of the background levels, and should provide the typical count of an otherwise empty pixel. The block must therefore accepts the two-dimensional image and returns either a single value -- the background count of the entire image, as calculated by the criteria of the specific block implementation -- or a 2D array of values, allowing for the possibility of varying background counts across the image. More information on this block can be found "background_estimator".

Culler and Ender

Only implemented in iterative fitting classes, part of the extension to ~photutils.psf.BasicPSFPhotometry, this block is the final step of a single iteration. While a maximum number of iterations can be specified for, e.g., ~photutils.psf.IterativelySubtractedPSFPhotometry, this block -- specifically, the ender half -- assesses whether all sources have been found within the image. If no new sources have been found within an iteration, fitting can be stopped prematurely, avoiding wasteful computational time. Similarly, the culler aspect of this block examines sources found within an iteration for quality; it should calculate some goodness-of-fit criterion and reject sources picked up by the Finder but fall below a given threshold. This block therefore accepts the sources output ~astropy.table.Table and returns a new ~astropy.table.Table with low quality sources -- such as cosmic ray hits present in the image -- removed as well as a boolean flag indicating whether the iterative fitting process has reached a conclusion and can be terminated. Please refer to the culler_and_ender documentation for further details.

Single Object Model

An additional block sitting between the PSF model and the Fitter_, the Single Object Model extends the fitting capability of the class from purely point-source objects to extended sources. This block, effectively, convolves the PSF of the given observation with a physical light distribution, producing the flux seen in each pixel by the system of such an extended source. This block therefore requires as its inputs the PSF model and the object type -- a string representing the type of source (point-like, spiral galaxy, etc.) to create the intrinsic light distribution for -- and returns a new ~astropy.modeling.Fittable2DModel instance, the convolution of the PSF and the true source. Further specifics on this block, including how it connects to Scene Maker can be found in the single object model documentation. This block is optional; if no additional physical object options are provided, the object type defaults to a point source and the input PSF model is returned.

Scene Maker

The final block within the scope of PSF fitting, the scene maker is also the last to be implemented. Currently no PSF fitting class extends its functionality to include this block, but it will eventually generalize and extend the Group Maker as the method of merging and assigning non-independent detections within a given image. While current grouping is simply the determining of point sources with potentially overlapping flux, the scene maker will allow for the grouping of both point sources into an overlapping, simultaneous fit group but also into a single extended object. Thus each iteration will require a step in which multiple-point-source extended objects are evaluated for their separation, and newly detected point sources are evaluated for potential assignment as part of an extended source. This block will be optional: if no additional object types are provided, all sources will be returned as point sources, as given by the group maker. The details of this block are available in the scene_maker docs, and will be expanded upon as the API is finalized.