LSST Applications 26.0.0,g0265f82a02+6660c170cc,g07994bdeae+30b05a742e,g0a0026dc87+17526d298f,g0a60f58ba1+17526d298f,g0e4bf8285c+96dd2c2ea9,g0ecae5effc+c266a536c8,g1e7d6db67d+6f7cb1f4bb,g26482f50c6+6346c0633c,g2bbee38e9b+6660c170cc,g2cc88a2952+0a4e78cd49,g3273194fdb+f6908454ef,g337abbeb29+6660c170cc,g337c41fc51+9a8f8f0815,g37c6e7c3d5+7bbafe9d37,g44018dc512+6660c170cc,g4a941329ef+4f7594a38e,g4c90b7bd52+5145c320d2,g58be5f913a+bea990ba40,g635b316a6c+8d6b3a3e56,g67924a670a+bfead8c487,g6ae5381d9b+81bc2a20b4,g93c4d6e787+26b17396bd,g98cecbdb62+ed2cb6d659,g98ffbb4407+81bc2a20b4,g9ddcbc5298+7f7571301f,ga1e77700b3+99e9273977,gae46bcf261+6660c170cc,gb2715bf1a1+17526d298f,gc86a011abf+17526d298f,gcf0d15dbbd+96dd2c2ea9,gdaeeff99f8+0d8dbea60f,gdb4ec4c597+6660c170cc,ge23793e450+96dd2c2ea9,gf041782ebf+171108ac67
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(flux_str, type="D", doc="Compensated Gaussian flux measurement.")
103
104 # flux error
105 err_str = f"{base_key}_instFluxErr"
106 err_key = schema.addField(err_str, type="D", doc="Compensated Gaussian flux error.")
107
108 # mask bits
109 mask_str = f"{base_key}_mask_bits"
110 mask_key = schema.addField(mask_str, type=np.int32, doc="Mask bits set within aperture.")
111
112 self.width_keys[width] = (flux_key, err_key, mask_key)
113 self._rads[width] = math.ceil(sps.norm.ppf((0.995,), scale=width * config.t)[0])
114
115 self._max_rad = max(self._rads)
116
117 def fail(self, measRecord, error=None):
118 if isinstance(error, OutOfBoundsError):
119 measRecord.set(self.ooBoundsKey, True)
120 measRecord.set(self.fatalFailKey, True)
121
122 def measure(self, measRecord, exposure):
123 center = measRecord.getCentroid()
124 bbox = exposure.getBBox()
125
126 if Point2I(center) not in exposure.getBBox().erodedBy(self._max_rad):
127 raise OutOfBoundsError("Not all the kernels for this source fit inside the exposure.")
128
129 y = center.getY() - bbox.beginY
130 x = center.getX() - bbox.beginX
131
132 y_floor = math.floor(y)
133 x_floor = math.floor(x)
134
135 for width, (flux_key, err_key, mask_key) in self.width_keys.items():
136 rad = self._rads[width]
137 y_slice = slice(y_floor - rad, y_floor + rad + 1, 1)
138 x_slice = slice(x_floor - rad, x_floor + rad + 1, 1)
139 y_mean = y - y_floor + rad
140 x_mean = x - x_floor + rad
141
142 flux, var = _compensatedGaussianFiltInnerProduct(
143 exposure.image.array[y_slice, x_slice],
144 exposure.variance.array[y_slice, x_slice],
145 x_mean,
146 y_mean,
147 width,
148 self._t,
149 )
150 measRecord.set(flux_key, flux)
151 measRecord.set(err_key, np.sqrt(var))
152 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)