LSST Applications 27.0.0,g0265f82a02+469cd937ee,g02d81e74bb+21ad69e7e1,g1470d8bcf6+cbe83ee85a,g2079a07aa2+e67c6346a6,g212a7c68fe+04a9158687,g2305ad1205+94392ce272,g295015adf3+81dd352a9d,g2bbee38e9b+469cd937ee,g337abbeb29+469cd937ee,g3939d97d7f+72a9f7b576,g487adcacf7+71499e7cba,g50ff169b8f+5929b3527e,g52b1c1532d+a6fc98d2e7,g591dd9f2cf+df404f777f,g5a732f18d5+be83d3ecdb,g64a986408d+21ad69e7e1,g858d7b2824+21ad69e7e1,g8a8a8dda67+a6fc98d2e7,g99cad8db69+f62e5b0af5,g9ddcbc5298+d4bad12328,ga1e77700b3+9c366c4306,ga8c6da7877+71e4819109,gb0e22166c9+25ba2f69a1,gb6a65358fc+469cd937ee,gbb8dafda3b+69d3c0e320,gc07e1c2157+a98bf949bb,gc120e1dc64+615ec43309,gc28159a63d+469cd937ee,gcf0d15dbbd+72a9f7b576,gdaeeff99f8+a38ce5ea23,ge6526c86ff+3a7c1ac5f1,ge79ae78c31+469cd937ee,gee10cc3b42+a6fc98d2e7,gf1cff7945b+21ad69e7e1,gfbcc870c63+9a11dc8c8f
LSST Data Management Base Package
Loading...
Searching...
No Matches
variance_plane.py
Go to the documentation of this file.
1# This file is part of meas_algorithms.
2#
3# LSST Data Management System
4# This product includes software developed by the
5# LSST Project (http://www.lsst.org/).
6# See COPYRIGHT file at the top of the source tree.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <https://www.lsstcorp.org/LegalNotices/>.
21#
22"""Utility functions related to the variance plane of Exposure objects. Tested
23in `ip_isr/tests/test_variance_plane.py` to avoid circular dependencies.
24"""
25
26import numpy as np
27
28__all__ = ["remove_signal_from_variance"]
29
30
31def remove_signal_from_variance(exposure, gain=None, gains=None, average_across_amps=False, in_place=False):
32 """
33 Removes the Poisson contribution from actual sources in the variance plane
34 of an Exposure.
35
36 If neither gain nor gains are provided, the function estimates the gain(s).
37 If ``average_across_amps`` is True, a single gain value for the entire
38 image is estimated. If False, individual gain values for each amplifier are
39 estimated. The estimation involves a linear fit of variance versus image
40 plane.
41
42 Parameters
43 ----------
44 exposure : `~lsst.afw.image.Exposure`
45 The background-subtracted exposure containing a variance plane to be
46 corrected for source contributions.
47 gain : `float`, optional
48 The gain value for the entire image. This parameter is used if
49 ``gains`` is not provided. If both ``gain`` and ``gains`` are None, and
50 ``average_across_amps`` is True, ``gain`` is estimated from the image
51 and variance planes.
52 gains : dict[`str`, `float`], optional
53 A dictionary mapping amplifier ID (as a string) to gain value. This
54 parameter is used if ``gain`` is not provided. If both ``gain`` and
55 ``gains`` are None, and ``average_across_amps`` is False, ``gains`` are
56 estimated from the image and variance planes.
57 average_across_amps : `bool`, optional
58 Determines the gain estimation strategy. If True, the gain for the
59 entire image is estimated at once. If False, individual gains for each
60 amplifier are estimated. This parameter is ignored if either ``gain``
61 or ``gains`` is specified.
62 in_place : `bool`, optional
63 If True, the variance plane of the input Exposure is modified in place.
64 A modified copy of the variance plane is always returned irrespective
65 of this.
66
67 Returns
68 -------
69 variance_plane : `~lsst.afw.image.Image`
70 The corrected variance plane, with the signal contribution removed.
71
72 Raises
73 ------
74 AttributeError
75 If amplifiers cannot be retrieved from the exposure.
76 ValueError
77 If both ``gain`` and ``gains`` are provided, or if the number of
78 provided ``gains`` does not match the number of amplifiers.
79 """
80 variance_plane = exposure.variance if in_place else exposure.variance.clone()
81 if gain is None and gains is None:
82 if average_across_amps:
83 amp_bboxes = [exposure.getBBox()]
84 else:
85 try:
86 amps = exposure.getDetector().getAmplifiers()
87 amp_bboxes = [amp.getBBox() for amp in amps]
88 except AttributeError:
89 raise AttributeError(
90 "Could not retrieve amplifiers from exposure. To compute a simple gain value across the "
91 "entire image, use average_across_amps=True."
92 )
93 # Fit a straight line to variance vs (sky-subtracted) signal. Then
94 # evaluate that line at zero signal to get an estimate of the
95 # signal-free variance.
96 for amp_bbox in amp_bboxes:
97 amp_im_arr = exposure[amp_bbox].image.array
98 amp_var_arr = variance_plane[amp_bbox].array
99 good = (amp_var_arr != 0) & np.isfinite(amp_var_arr) & np.isfinite(amp_im_arr)
100 fit = np.polyfit(amp_im_arr[good], amp_var_arr[good], deg=1)
101 # Fit is [1/gain, sky_var].
102 amp_gain = 1.0 / fit[0]
103 variance_plane[amp_bbox].array[good] -= amp_im_arr[good] / amp_gain
104 elif gain is None and gains is not None:
105 amps = exposure.getDetector().getAmplifiers()
106 namps = len(amps)
107 if len(gains) != namps:
108 raise ValueError(
109 f"Incorrect number of gains provided: {len(gains)} values for {namps} amplifiers."
110 )
111 for amp in amps:
112 amp_bbox = amp.getBBox()
113 amp_gain = gains[amp.getName()]
114 im_arr = exposure[amp_bbox].image.array
115 variance_plane[amp_bbox].array -= im_arr / amp_gain
116 elif gain is not None and gains is None:
117 im_arr = exposure.image.array
118 variance_plane.array -= im_arr / gain
119 elif gain is not None and gains is not None:
120 raise ValueError(
121 "Both 'gain' and 'gains' are provided. Please provide only one of them or none at "
122 "all in case of automatic gain estimation from the image and variance planes."
123 )
124 # Check that the variance plane has no negative values.
125 if np.any(variance_plane.array < 0):
126 raise ValueError("Corrected variance plane has negative values.")
127 return variance_plane
remove_signal_from_variance(exposure, gain=None, gains=None, average_across_amps=False, in_place=False)