PSF photometry

Threshold-ladder PSF fitter, joint-refit, NNLS forced-photometry refit, and the leftover-detection loop.

sphot.psf.get_full_traceback(e)[source]

Get the full traceback of an exception as a string.

class sphot.psf.PSFFitter(cutoutdata)[source]

Bases: object

A class to perform PSF fitting.

psf_img2model(psfimg, psf_oversample)[source]
fit(fit_to='sersic_residual', **kwargs)[source]

Perform PSF fitting via iterative_psf_fitting (wraps do_psf_photometry with a threshold ladder so we don’t fit >1000 sources simultaneously in crowded fields).

The PSF used is cutoutdata.psf as-is. Mainloop-level kernel calibration (_maybe_recalibrate_psf -> calibrate_psf_step) updates cutoutdata.psf with library * K between iterations; this fitter just reads the current PSF state and runs the ladder.

Parameters:
  • fit_to (str) – attribute name of the image to fit, e.g. ‘sersic_residual’, ‘residual’, ‘data’.

  • kwargs (dict) – extra kwargs forwarded to do_psf_photometry.

Returns:

CutoutData – updated in-place.

sphot.psf.filter_psfphot_results(phot_result, center_mask_params=None, full_output=False, bkg_std=None, **kwargs)[source]

Filter the PSF photometry results.

sphot.psf.sigma_clip_outside_aperture(data, sersic_params_physical, clip_sigma=4, aper_size_in_r_eff=1)[source]
sphot.psf.subtract_background(data)[source]

Subtract background from data. This removes most of the large-scale background variations.

sphot.psf.do_psf_photometry(data, data_error, bkg_std, psf_model, psf_sigma, th=2, plot=True, mask=None, **kwargs)[source]

Performs PSF photometry. Main function to run PSF photometry.

This function does the following:

  1. turn psfimg into a fittable model

  2. estimate the background statistics (mean, std)

  3. subtract background from data

  4. perform IterativePSFPhotometry with the finder threshold at th*std

  5. filter the results based on the fit quality (cfit, qfit, flux_err)

  6. perform PSFPhotometry using the filtered results as input

  7. filter the results again

  8. generate model image and residual image

  9. plot the results if necessary

Parameters:
  • data (2d array) – the data to perform PSF photometry.

  • psfimg (2d array) – the PSF image.

  • psf_sigma (float) – the HWHM of the PSF. Use FWHM/2

  • psf_oversample (int) – the oversampling factor of the PSF.

  • th (float) – the detection threshold in background STD.

  • Niter (int) – the number of iterations to repeat the photometry (after cleaning up the data). – !deprecated!

  • fit_shape (2-tuple) – the shape of the fit.

  • render_shape (2-tuple) – the shape of each PSF to be rendered.

  • finder_kwargs (dict,optional) – the kwargs for DAOStarFinder.

  • localbkg_bounds (2-tuple,optional) – (inner, outer) radii to LocalBackground object, in the unit of psf_sigma.

  • grouper_sep (float,optional) – the minimum separation between sources to be used for SourceGrouper.

Returns:
  • phot_result (QTable) – the photometry result.

  • resid (2d array) – the residual image.

sphot.psf.iterative_psf_fitting(data, psf_model, psf_sigma, threshold_list, progress=None, progress_text='Running iPSF...', **kwargs)[source]

Iteratively run do_psf_photometry() with different threshold levels. This function is useful for crowded fields, where a single threshold level may fail.

The threshold list is typically descending (high -> low). Each successful pass subtracts detected sources from the residual; the next pass then operates on the cleaner residual. The ladder early-exits when th_max_consec_empty consecutive thresholds add no new sources.

Parameters:
  • data (2d array) – the data to perform PSF photometry.

  • psf_model – the PSF ImagePSF model.

  • psf_sigma (float) – the HWHM of the PSF. Use FWHM/2

  • threshold_list (1d array) – the list of threshold levels to try, in background STD.

  • center_mask_params (list, optional) – [x_center, y_center, mask_r]. If provided, sources within mask_r from (x_center, y_center) are excluded from the final results. Useful when the central source is very bright and causes many spurious detections nearby.

  • kwargs (dict) – additional kwargs to pass to do_psf_photometry.

Returns:
  • phot_result (QTable) – the combined photometry result from all iterations.

  • resid_all (2d array) – the final residual image.

sphot.psf.forced_psf_photometry(data, psf_model, psf_sigma, x_init, y_init, *, flux_init=None, xy_bound=1e-06, center_mask_params=None, progress=None, progress_text='forced PSF photometry')[source]

Closed-form NNLS forced photometry at FIXED positions.

Bypasses photutils’ PSFPhotometry entirely — that path uses a SourceGrouper + LM that scales poorly when many positions fall inside one wide-PSF group (e.g. F160W with ~556 base-filter positions can hang for hours in a single mega-group LM).

Recipe (same as _final_nnls_refit’s inner solve): render each source’s unit-flux PSF on the full image to form a column of the design matrix, then solve data = cols @ flux jointly via NNLS (Gram + Cholesky, with a dense fallback). One call, fast.

Parameters:
  • data (2D ndarray) – Image to fit (typically cd.sersic_residual).

  • psf_model (photutils ImagePSF) – Effective PSF model.

  • psf_sigma (float) – Used only for the xy_bound legacy arg (no LM here).

  • x_init, y_init (1D float arrays) – Pinned source positions in data px.

  • flux_init (ignored (NNLS doesn’t need a flux seed).)

  • xy_bound (ignored (positions are FIXED in NNLS).)

  • center_mask_params ([x_c, y_c, r] | None) – Pixels inside this radius of the Sersic core are masked.

Returns:
  • phot_table (QTable with x_fit, y_fit, flux_fit, flux_err, flags)

  • resid_image (data - model_image (full-frame, NaNs preserved))

sphot.psf.run_forced_photometry_on_cutout(cutoutdata, x_init, y_init, *, flux_init=None, fit_to='sersic_residual', xy_bound=1e-06, progress=None)[source]

Run forced_psf_photometry on a CutoutData and populate the same downstream attrs PSFFitter.fit writes (residual, psf_table, psf_modelimg, psf_sub_data, psf_sub_data_error, residual_masked).

Used as a drop-in replacement for PSFFitter.fit inside run_scalefit_forced so the rest of the pipeline (sersic re-fit, plotting, save) sees the same set of attributes regardless of whether iPSF or forced photometry produced them.