/usr/lib/python3/dist-packages/photutils/utils/errors.py is in python3-photutils 0.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | # Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import numpy as np
import astropy.units as u
from astropy.utils.misc import isiterable
__all__ = ['calc_total_error']
def calc_total_error(data, bkg_error, effective_gain):
"""
Calculate a total error array, combining a background-only error
array with the Poisson noise of sources.
Parameters
----------
data : array_like or `~astropy.units.Quantity`
The data array.
bkg_error : array_like or `~astropy.units.Quantity`
The pixel-wise Gaussian 1-sigma background-only errors of the
input ``data``. ``bkg_error`` should include all sources of
"background" error but *exclude* the Poisson error of the
sources. ``bkg_error`` must have the same shape as ``data``.
If ``data`` and ``bkg_error`` are `~astropy.units.Quantity`
objects, then they must have the same units.
effective_gain : float, array-like, or `~astropy.units.Quantity`
Ratio of counts (e.g., electrons or photons) to the units of
``data`` used to calculate the Poisson error of the sources.
Returns
-------
total_error : `~numpy.ndarray` or `~astropy.units.Quantity`
The total error array. If ``data``, ``bkg_error``, and
``effective_gain`` are all `~astropy.units.Quantity` objects,
then ``total_error`` will also be returned as a
`~astropy.units.Quantity` object with the same units as the
input ``data``. Otherwise, a `~numpy.ndarray` will be returned.
Notes
-----
To use units, ``data``, ``bkg_error``, and ``effective_gain`` must
*all* be `~astropy.units.Quantity` objects. ``data`` and
``bkg_error`` must have the same units. A `ValueError` will be
raised if only some of the inputs are `~astropy.units.Quantity`
objects or if the ``data`` and ``bkg_error`` units differ.
The total error array, :math:`\\sigma_{\\mathrm{tot}}` is:
.. math:: \\sigma_{\\mathrm{tot}} = \\sqrt{\\sigma_{\\mathrm{b}}^2 +
\\frac{I}{g}}
where :math:`\\sigma_b`, :math:`I`, and :math:`g` are the background
``bkg_error`` image, ``data`` image, and ``effective_gain``,
respectively.
Pixels where ``data`` (:math:`I_i)` is negative do not contribute
additional Poisson noise to the total error, i.e.
:math:`\\sigma_{\\mathrm{tot}, i} = \\sigma_{\\mathrm{b}, i}`. Note
that this is different from `SExtractor`_, which sums the total
variance in the segment, including pixels where :math:`I_i` is
negative. In such cases, `SExtractor`_ underestimates the total
errors. Also note that SExtractor computes Poisson errors from
background-subtracted data, which also results in an underestimation
of the Poisson noise.
``effective_gain`` can either be a scalar value or a 2D image with
the same shape as the ``data``. A 2D image is useful with mosaic
images that have variable depths (i.e., exposure times) across the
field. For example, one should use an exposure-time map as the
``effective_gain`` for a variable depth mosaic image in count-rate
units.
As an example, if your input ``data`` are in units of ADU, then
``effective_gain`` should be in units of electrons/ADU (or
photons/ADU). If your input ``data`` are in units of electrons/s
then ``effective_gain`` should be the exposure time or an exposure
time map (e.g., for mosaics with non-uniform exposure times).
.. _SExtractor: http://www.astromatic.net/software/sextractor
"""
data = np.asanyarray(data)
bkg_error = np.asanyarray(bkg_error)
inputs = [data, bkg_error, effective_gain]
has_unit = [hasattr(x, 'unit') for x in inputs]
use_units = all(has_unit)
if any(has_unit) and not use_units:
raise ValueError('If any of data, bkg_error, or effective_gain has '
'units, then they all must all have units.')
if use_units:
if data.unit != bkg_error.unit:
raise ValueError('data and bkg_error must have the same units.')
count_units = [u.electron, u.photon]
datagain_unit = data.unit * effective_gain.unit
if datagain_unit not in count_units:
raise u.UnitsError('(data * effective_gain) has units of "{0}", '
'but it must have count units (e.g. '
'u.electron or u.photon).'
.format(datagain_unit))
if not isiterable(effective_gain):
effective_gain = np.zeros(data.shape) + effective_gain
else:
effective_gain = np.asanyarray(effective_gain)
if effective_gain.shape != data.shape:
raise ValueError('If input effective_gain is 2D, then it must '
'have the same shape as the input data.')
if np.any(effective_gain <= 0):
raise ValueError('effective_gain must be strictly positive '
'everywhere.')
# This calculation assumes that data and bkg_error have the same
# units. source_variance is calculated to have units of
# (data.unit)**2 so that it can be added with bkg_error**2 below. The
# final returned error will have units of data.unit. np.maximum is
# used to ensure that negative data values do not contribute to the
# Poisson noise.
if use_units:
unit = data.unit
data = data.value
effective_gain = effective_gain.value
source_variance = np.maximum(data / effective_gain, 0) * unit**2
else:
source_variance = np.maximum(data / effective_gain, 0)
return np.sqrt(bkg_error**2 + source_variance)
|