LSST Applications g180d380827+6621f76652,g2079a07aa2+86d27d4dc4,g2305ad1205+f5a9e323a1,g2bbee38e9b+c6a8a0fb72,g337abbeb29+c6a8a0fb72,g33d1c0ed96+c6a8a0fb72,g3a166c0a6a+c6a8a0fb72,g3ddfee87b4+9a10e1fe7b,g48712c4677+c9a099281a,g487adcacf7+f2e03ea30b,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+aead732c78,g64a986408d+eddffb812c,g858d7b2824+eddffb812c,g864b0138d7+aa38e45daa,g974c55ee3d+f37bf00e57,g99cad8db69+119519a52d,g9c22b2923f+e2510deafe,g9ddcbc5298+9a081db1e4,ga1e77700b3+03d07e1c1f,gb0e22166c9+60f28cb32d,gb23b769143+eddffb812c,gba4ed39666+c2a2e4ac27,gbb8dafda3b+27317ec8e9,gbd998247f1+585e252eca,gc120e1dc64+5817c176a8,gc28159a63d+c6a8a0fb72,gc3e9b769f7+6707aea8b4,gcf0d15dbbd+9a10e1fe7b,gdaeeff99f8+f9a426f77a,ge6526c86ff+6a2e01d432,ge79ae78c31+c6a8a0fb72,gee10cc3b42+585e252eca,gff1a9f87cc+eddffb812c,v27.0.0.rc1
LSST Data Management Base Package
Loading...
Searching...
No Matches
_compensatedGaussian.py
Go to the documentation of this file.
1# This file is part of meas_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22from __future__ import annotations
23
24__all__ = (
25 "SingleFrameCompensatedGaussianFluxConfig",
26 "SingleFrameCompensatedGaussianFluxPlugin",
27)
28
29import math
30import numpy as np
31import scipy.stats as sps
32
33from lsst.pex.config import Field, ListField
34from lsst.geom import Point2I
35
36from ..sfm import SingleFramePlugin, SingleFramePluginConfig
37from ..pluginRegistry import register
38
39from .._measBaseLib import _compensatedGaussianFiltInnerProduct
40
41
42class OutOfBoundsError(Exception):
43 pass
44
45
47 kernel_widths = ListField(
48 doc="The widths (in pixels) of the kernels for which to measure compensated apertures.",
49 dtype=int,
50 minLength=1,
51 default=[3, 5]
52 )
53
54 t = Field(
55 doc="Scale parameter of outer Gaussian compared to inner Gaussian.",
56 dtype=float,
57 default=2.0,
58 )
59
60
61@register("base_CompensatedGaussianFlux")
63 ConfigClass = SingleFrameCompensatedGaussianFluxConfig
64
65 @classmethod
67 return cls.FLUX_ORDER
68
70 self,
71 config: SingleFrameCompensatedGaussianFluxConfig,
72 name: str,
73 schema,
74 metadata,
75 logName=None,
76 **kwds,
77 ):
78 super().__init__(config, name, schema, metadata, logName, **kwds)
79
80 # create generic failure key
81 self.fatalFailKey = schema.addField(
82 f"{name}_flag", type="Flag", doc="Set to 1 for any fatal failure."
83 )
84
85 # Out of bounds failure key
86 self.ooBoundsKey = schema.addField(
87 f"{name}_bounds_flag",
88 type="Flag",
89 doc="Flag set to 1 if not all filters fit within exposure.",
90 )
91
92 self.width_keys = {}
93 self._rads = {}
96 self._t = config.t
97 for width in config.kernel_widths:
98 base_key = f"{name}_{width}"
99
100 # flux
101 flux_str = f"{base_key}_instFlux"
102 flux_key = schema.addField(
103 flux_str,
104 type="D",
105 doc="Compensated Gaussian flux measurement.",
106 units="count",
107 )
108
109 # flux error
110 err_str = f"{base_key}_instFluxErr"
111 err_key = schema.addField(
112 err_str,
113 type="D",
114 doc="Compensated Gaussian flux error.",
115 units="count",
116 )
117
118 # mask bits
119 mask_str = f"{base_key}_mask_bits"
120 mask_key = schema.addField(mask_str, type=np.int32, doc="Mask bits set within aperture.")
121
122 self.width_keys[width] = (flux_key, err_key, mask_key)
123 self._rads[width] = math.ceil(sps.norm.ppf((0.995,), scale=width * config.t)[0])
124
125 self._max_rad = max(self._rads)
126
127 def fail(self, measRecord, error=None):
128 if isinstance(error, OutOfBoundsError):
129 measRecord.set(self.ooBoundsKey, True)
130 measRecord.set(self.fatalFailKey, True)
131
132 def measure(self, measRecord, exposure):
133 center = measRecord.getCentroid()
134 bbox = exposure.getBBox()
135
136 if Point2I(center) not in exposure.getBBox().erodedBy(self._max_rad):
137 raise OutOfBoundsError("Not all the kernels for this source fit inside the exposure.")
138
139 y = center.getY() - bbox.beginY
140 x = center.getX() - bbox.beginX
141
142 y_floor = math.floor(y)
143 x_floor = math.floor(x)
144
145 for width, (flux_key, err_key, mask_key) in self.width_keys.items():
146 rad = self._rads[width]
147 y_slice = slice(y_floor - rad, y_floor + rad + 1, 1)
148 x_slice = slice(x_floor - rad, x_floor + rad + 1, 1)
149 y_mean = y - y_floor + rad
150 x_mean = x - x_floor + rad
151
152 flux, var = _compensatedGaussianFiltInnerProduct(
153 exposure.image.array[y_slice, x_slice],
154 exposure.variance.array[y_slice, x_slice],
155 x_mean,
156 y_mean,
157 width,
158 self._t,
159 )
160 measRecord.set(flux_key, flux)
161 measRecord.set(err_key, np.sqrt(var))
162 measRecord.set(mask_key, np.bitwise_or.reduce(exposure.mask.array[y_slice, x_slice], axis=None))
std::vector< SchemaItem< Flag > > * items
int max
__init__(self, SingleFrameCompensatedGaussianFluxConfig config, str name, schema, metadata, logName=None, **kwds)