decode_psf_flags#

photutils.psf.decode_psf_flags(flags, return_bit_values=False)[source]#

Decode PSF photometry bit flags into individual components.

This function takes integer flag values from PSF photometry results and returns a list of human-readable descriptions of the issues that occurred during fitting. This is useful for understanding what problems were encountered without needing to manually perform bitwise operations.

Parameters:
flagsint or array-like of int

Integer flag value(s) to decode. Each bit in the flag represents a specific condition that occurred during PSF fitting.

return_bit_valuesbool, optional

If True, return the decoded bit flags (integers) instead of the flag descriptions (strings). Default is False.

Returns:
decodedlist of str, list of int, or nested list

List of active flag names (or bit values) for a scalar input. For an array input, a nested list with the same shape as the input is returned, where each innermost element is the list of active flag names (or bit values) for the corresponding flag. Each string (or integer) represents a specific condition that was detected during PSF fitting. If no flags are set, an empty list is returned. Possible flags are:

  • 0 : No flags set.

  • 1 ('n_pixels_fit_partial') : The number of fitted pixels (n_pixels_fit) is smaller than the full fit_shape region, indicating partial PSF fitting.

  • 2 ('outside_bounds') : The fitted source position is outside the bounds of the input image.

  • 4 ('negative_flux') : The fitted flux value is negative or zero, which is non-physical.

  • 8 ('no_convergence') : The PSF fitting algorithm may not have converged to a stable solution.

  • 16 ('no_covariance') : Parameter covariance matrix is not available, preventing error estimation.

  • 32 ('near_bound') : One or more fitted parameters are very close to their imposed bounds.

  • 64 ('no_overlap') : The source PSF fitting region has no overlap with valid data pixels.

  • 128 ('fully_masked') : All pixels in the source fitting region are masked.

  • 256 ('too_few_pixels') : Insufficient unmasked pixels available for reliable PSF fitting.

  • 512 ('non_finite_position') : The fitted x or y position is NaN or inf, indicating an invalid or failed fit.

  • 1024 ('non_finite_flux') : The fitted flux value is NaN or inf, indicating an invalid or failed fit.

  • 2048 ('non_finite_localbkg') : The local background value is NaN or inf, so it was not subtracted before fitting.

Examples

Decode a single flag value:

>>> from photutils.psf import decode_psf_flags
>>> issues = decode_psf_flags(5)  # bits 1 and 4 set
>>> print(issues)
['n_pixels_fit_partial', 'negative_flux']
>>> 'n_pixels_fit_partial' in issues
True
>>> 'no_convergence' in issues
False

Decode multiple flag values:

>>> flags = [0, 8, 136]  # 0, bit 8, bits 8+128
>>> decoded_list = decode_psf_flags(flags)
>>> len(decoded_list)
3
>>> decoded_list[0]  # No issues
[]
>>> decoded_list[1]  # Convergence issue
['no_convergence']
>>> decoded_list[2]  # Multiple issues
['no_convergence', 'fully_masked']

Check for specific issues:

>>> issues = decode_psf_flags(136)
>>> if 'no_convergence' in issues:
...     print("Fit may not have converged")
Fit may not have converged
>>> if issues:  # Any issues present
...     print(f"Found {len(issues)} issues: {', '.join(issues)}")
Found 2 issues: no_convergence, fully_masked

Working with PSF photometry results:

>>> import numpy as np
>>> from astropy.modeling import models
>>> from astropy.table import Table
>>> from photutils.psf import (CircularGaussianPRF, PSFPhotometry,
...                            decode_psf_flags)
>>> # Create minimal test data
>>> yy, xx = np.mgrid[:21, :21]
>>> m1 = CircularGaussianPRF(flux=-10, x_0=10, y_0=10, fwhm=2)
>>> m2 = CircularGaussianPRF(flux=10, x_0=3, y_0=3, fwhm=2)
>>> m3 = CircularGaussianPRF(flux=10, x_0=21, y_0=21, fwhm=2)
>>> data = m1(xx, yy) + m2(xx, yy) + m3(xx, yy)
>>> psf_model = CircularGaussianPRF(flux=1, x_0=10, y_0=10, fwhm=2)
>>> init_params = Table({'x': (10, 3, 21), 'y': (10, 3, 21),
...                      'flux': (1, 10, 10)})
>>> photometry = PSFPhotometry(psf_model, (3, 3))
>>> results = photometry(data, init_params=init_params)
>>> issues_list = decode_psf_flags(results['flags'])
>>> for i, issues in enumerate(issues_list):
...     if issues:
...         print(f"Source {i+1}: {', '.join(issues)}")
Source 1: negative_flux
Source 3: n_pixels_fit_partial, no_covariance, too_few_pixels, non_finite_position, non_finite_flux