LSST Applications g04e9c324dd+8c5ae1fdc5,g134cb467dc+1b3060144d,g18429d2f64+f642bf4753,g199a45376c+0ba108daf9,g1fd858c14a+2dcf163641,g262e1987ae+7b8c96d2ca,g29ae962dfc+3bd6ecb08a,g2cef7863aa+aef1011c0b,g35bb328faa+8c5ae1fdc5,g3fd5ace14f+53e1a9e7c5,g4595892280+fef73a337f,g47891489e3+2efcf17695,g4d44eb3520+642b70b07e,g53246c7159+8c5ae1fdc5,g67b6fd64d1+2efcf17695,g67fd3c3899+b70e05ef52,g74acd417e5+317eb4c7d4,g786e29fd12+668abc6043,g87389fa792+8856018cbb,g89139ef638+2efcf17695,g8d7436a09f+3be3c13596,g8ea07a8fe4+9f5ccc88ac,g90f42f885a+a4e7b16d9b,g97be763408+ad77d7208f,g9dd6db0277+b70e05ef52,ga681d05dcb+a3f46e7fff,gabf8522325+735880ea63,gac2eed3f23+2efcf17695,gb89ab40317+2efcf17695,gbf99507273+8c5ae1fdc5,gd8ff7fe66e+b70e05ef52,gdab6d2f7ff+317eb4c7d4,gdc713202bf+b70e05ef52,gdfd2d52018+b10e285e0f,ge365c994fd+310e8507c4,ge410e46f29+2efcf17695,geaed405ab2+562b3308c0,gffca2db377+8c5ae1fdc5,w.2025.35
LSST Data Management Base Package
Loading...
Searching...
No Matches
_aggregates.cc
Go to the documentation of this file.
1/*
2 * This file is part of afw.
3 *
4 * Developed for the LSST Data Management System.
5 * This product includes software developed by the LSST Project
6 * (https://www.lsst.org).
7 * See the COPYRIGHT file at the top-level directory of this distribution
8 * for details of code ownership.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include "pybind11/pybind11.h"
25#include "pybind11/eigen.h"
26#include "pybind11/stl.h"
27
28#include "ndarray/pybind11.h"
29
31
33#include "lsst/geom/Angle.h"
35#include "lsst/geom/Box.h"
36#include "lsst/afw/table/Key.h"
41
42namespace py = pybind11;
43using namespace pybind11::literals;
44
45namespace lsst {
46namespace afw {
47namespace table {
48
49using cpputils::python::WrapperCollection;
50
51namespace {
52
53// We don't expose base classes (e.g. FunctorKey) to Python, since they're just used to
54// define a CRTP interface in C++ and in Python that's just duck-typing.
55
56template <typename T>
57using PyPointKey = py::classh<PointKey<T>>;
58
59template <typename T>
60using PyPoint3Key = py::classh<Point3Key<T>>;
61
62template <typename Box>
63using PyBoxKey = py::classh<BoxKey<Box>>;
64
65using PyCoordKey = py::classh<CoordKey>;
66
67using PyQuadrupoleKey = py::classh<QuadrupoleKey>;
68
69using PyEllipseKey = py::classh<EllipseKey>;
70
71template <typename T, int N>
72using PyCovarianceMatrixKey = py::classh<CovarianceMatrixKey<T, N>>;
73
74template <typename T>
75static void declarePointKey(WrapperCollection &wrappers, std::string const &suffix) {
76 wrappers.wrapType(
77 PyPointKey<T>(wrappers.module, ("Point" + suffix + "Key").c_str()), [](auto &mod, auto &cls) {
78 cls.def(py::init<>());
79 cls.def(py::init<Key<T> const &, Key<T> const &>(), "x"_a, "y"_a);
80 cls.def(py::init<SubSchema const &>());
81 cls.def("__eq__", &PointKey<T>::operator==, py::is_operator());
82 cls.def("__ne__", &PointKey<T>::operator!=, py::is_operator());
83 cls.def("getX", &PointKey<T>::getX);
84 cls.def("getY", &PointKey<T>::getY);
85 cls.def("isValid", &PointKey<T>::isValid);
86 cls.def_static("addFields", &PointKey<T>::addFields, "schema"_a, "name"_a, "doc"_a, "unit"_a);
87 cls.def("set", [](PointKey<T> &self, BaseRecord &record,
88 lsst::geom::Point<T, 2> const &value) { return self.set(record, value); });
89 cls.def("get", &PointKey<T>::get);
90 });
91};
92
93template <typename T>
94static void declarePoint3Key(WrapperCollection &wrappers, std::string const &suffix) {
95 wrappers.wrapType(
96 PyPoint3Key<T>(wrappers.module, ("Point3" + suffix + "Key").c_str()), [](auto &mod, auto &cls) {
97 cls.def(py::init<>());
98 cls.def(py::init<Key<T> const &, Key<T> const &, Key<T> const &>(), "x"_a, "y"_a, "z"_a);
99 cls.def(py::init<SubSchema const &>());
100 cls.def("__eq__", &Point3Key<T>::operator==, py::is_operator());
101 cls.def("__ne__", &Point3Key<T>::operator!=, py::is_operator());
102 cls.def("getX", &Point3Key<T>::getX);
103 cls.def("getY", &Point3Key<T>::getY);
104 cls.def("isValid", &Point3Key<T>::isValid);
105 cls.def_static("addFields", &Point3Key<T>::addFields, "schema"_a, "name"_a, "doc"_a, "unit"_a);
106 cls.def("set", [](Point3Key<T> &self, BaseRecord &record,
107 lsst::geom::Point<T, 3> const &value) { return self.set(record, value); });
108 cls.def("get", &Point3Key<T>::get);
109 });
110};
111
112template <typename Box>
113static void declareBoxKey(WrapperCollection &wrappers, std::string const &suffix) {
114 wrappers.wrapType(
115 PyBoxKey<Box>(wrappers.module, ("Box" + suffix + "Key").c_str()), [](auto &mod, auto &cls) {
116 using Element = typename Box::Element;
117 cls.def(py::init<>());
118 cls.def(py::init<PointKey<Element> const &, PointKey<Element> const &>(), "min"_a, "max"_a);
119 cls.def(py::init<SubSchema const &>());
120 cls.def("__eq__", &BoxKey<Box>::operator==, py::is_operator());
121 cls.def("__ne__", &BoxKey<Box>::operator!=, py::is_operator());
122 cls.def("getMin", &BoxKey<Box>::getMin);
123 cls.def("getMax", &BoxKey<Box>::getMax);
124 cls.def("isValid", &BoxKey<Box>::isValid);
125 cls.def_static("addFields", &BoxKey<Box>::addFields, "schema"_a, "name"_a, "doc"_a, "unit"_a);
126 cls.def("set", &BoxKey<Box>::set);
127 cls.def("get", &BoxKey<Box>::get);
128
129 });
130};
131
132static void declareCoordKey(WrapperCollection &wrappers) {
133 wrappers.wrapType(PyCoordKey(wrappers.module, "CoordKey"), [](auto &mod, auto &cls) {
134 cls.def(py::init<>());
135 cls.def(py::init<Key<lsst::geom::Angle>, Key<lsst::geom::Angle>>(), "ra"_a, "dec"_a);
136 cls.def(py::init<SubSchema const &>());
137 cls.def("__eq__", &CoordKey::operator==, py::is_operator());
138 cls.def("__ne__", &CoordKey::operator!=, py::is_operator());
139 cls.def_static("addFields", &CoordKey::addFields, "schema"_a, "name"_a, "doc"_a);
140 cls.def_static("addErrorFields", &CoordKey::addErrorFields, "schema"_a);
141 cls.def_static("getErrorKey", &CoordKey::getErrorKey, "schema"_a);
142 cls.def("getRa", &CoordKey::getRa);
143 cls.def("getDec", &CoordKey::getDec);
144 cls.def("isValid", &CoordKey::isValid);
145 cls.def("get", [](CoordKey &self, BaseRecord const &record) { return self.get(record); });
146 cls.def("set", &CoordKey::set);
147 });
148}
149
150static void declareQuadrupoleKey(WrapperCollection &wrappers) {
151 wrappers.wrapType(PyQuadrupoleKey(wrappers.module, "QuadrupoleKey"), [](auto &mod, auto &cls) {
152 cls.def(py::init<>());
153 cls.def(py::init<Key<double> const &, Key<double> const &, Key<double> const &>(), "ixx"_a, "iyy"_a,
154 "ixy"_a);
155 cls.def(py::init<SubSchema const &>());
156 cls.def("__eq__", &QuadrupoleKey::operator==, py::is_operator());
157 cls.def("__nq__", &QuadrupoleKey::operator!=, py::is_operator());
158 cls.def_static("addFields", &QuadrupoleKey::addFields, "schema"_a, "name"_a, "doc"_a,
159 "coordType"_a = CoordinateType::PIXEL);
160 cls.def("getIxx", &QuadrupoleKey::getIxx);
161 cls.def("getIyy", &QuadrupoleKey::getIyy);
162 cls.def("getIxy", &QuadrupoleKey::getIxy);
163 cls.def("isValid", &QuadrupoleKey::isValid);
164 cls.def("set", &QuadrupoleKey::set);
165 cls.def("get", &QuadrupoleKey::get);
166 });
167}
168
169static void declareEllipseKey(WrapperCollection &wrappers) {
170 wrappers.wrapType(PyEllipseKey(wrappers.module, "EllipseKey"), [](auto &mod, auto &cls) {
171 cls.def(py::init<>());
172 cls.def(py::init<QuadrupoleKey const &, PointKey<double> const &>(), "qKey"_a, "pKey"_a);
173 cls.def(py::init<SubSchema const &>());
174 cls.def("__eq__", &EllipseKey::operator==, py::is_operator());
175 cls.def("__nq__", &EllipseKey::operator!=, py::is_operator());
176 cls.def_static("addFields", &EllipseKey::addFields, "schema"_a, "name"_a, "doc"_a, "unit"_a);
177 cls.def("get", &EllipseKey::get);
178 cls.def("set", &EllipseKey::set);
179 cls.def("isValid", &EllipseKey::isValid);
180 cls.def("getCore", &EllipseKey::getCore);
181 cls.def("getCenter", &EllipseKey::getCenter);
182 });
183}
184
185template <typename T, int N>
186static void declareCovarianceMatrixKey(WrapperCollection &wrappers, const ::std::string &suffix) {
187 wrappers.wrapType(
188 PyCovarianceMatrixKey<T, N>(wrappers.module, ("CovarianceMatrix" + suffix + "Key").c_str()),
189 [](auto &mod, auto &cls) {
190 using ErrKeyArray = std::vector<Key<T>>;
191 using CovarianceKeyArray = std::vector<Key<T>>;
192 using NameArray = std::vector<std::string>;
193
194 cls.def(py::init<>());
195 // Ordering of the next two ctor declaration matters, as a workaround for DM-8580.
196 cls.def(py::init<SubSchema const &, NameArray const &>());
197 cls.def(py::init<ErrKeyArray const &, CovarianceKeyArray const &>(), "err"_a,
198 "cov"_a = CovarianceKeyArray());
199 cls.def("__eq__", &CovarianceMatrixKey<T, N>::operator==, py::is_operator());
200 cls.def("__ne__", &CovarianceMatrixKey<T, N>::operator!=, py::is_operator());
201 cls.def_static("addFields",
202 (CovarianceMatrixKey<T, N>(*)(Schema &, std::string const &, NameArray const &,
203 std::string const &, bool)) &
204 CovarianceMatrixKey<T, N>::addFields,
205 "schema"_a, "prefix"_a, "names"_a, "unit"_a, "diagonalOnly"_a = false);
206 cls.def_static("addFields",
207 (CovarianceMatrixKey<T, N>(*)(Schema &, std::string const &, NameArray const &,
208 NameArray const &, bool)) &
209 CovarianceMatrixKey<T, N>::addFields,
210 "schema"_a, "prefix"_a, "names"_a, "units"_a, "diagonalOnly"_a = false);
211 cls.def("set", [](CovarianceMatrixKey<T, N> &cov, BaseRecord &record,
212 Eigen::Matrix<T, N, N> const &value) { return cov.set(record, value); });
213 cls.def("get", [](CovarianceMatrixKey<T, N> &cov, BaseRecord const &record) {
214 return cov.get(record);
215 });
216 cls.def("isValid", &CovarianceMatrixKey<T, N>::isValid);
217 cls.def("setElement", &CovarianceMatrixKey<T, N>::setElement);
218 cls.def("getElement", &CovarianceMatrixKey<T, N>::getElement);
219 });
220}
221
222} // namespace
223
225 // TODO: uncomment once afw.geom uses WrapperCollection
226 // wrappers.addSignatureDependency("lsst.afw.geom.ellipses");
227
228 wrappers.wrapType(py::enum_<CoordinateType>(wrappers.module, "CoordinateType"), [](auto &mod, auto &enm) {
229 enm.value("PIXEL", CoordinateType::PIXEL);
230 enm.value("CELESTIAL", CoordinateType::CELESTIAL);
231 enm.export_values();
232 });
233
234 declarePointKey<double>(wrappers, "2D");
235 declarePointKey<int>(wrappers, "2I");
236 declarePoint3Key<double>(wrappers, "D");
237 declarePoint3Key<int>(wrappers, "I");
238
239 declareBoxKey<lsst::geom::Box2D>(wrappers, "2D");
240 declareBoxKey<lsst::geom::Box2I>(wrappers, "2I");
241
242 declareCoordKey(wrappers);
243 declareQuadrupoleKey(wrappers);
244 declareEllipseKey(wrappers);
245
246 declareCovarianceMatrixKey<float, 2>(wrappers, "2f");
247 declareCovarianceMatrixKey<float, 3>(wrappers, "3f");
248 declareCovarianceMatrixKey<float, 4>(wrappers, "4f");
249 declareCovarianceMatrixKey<float, Eigen::Dynamic>(wrappers, "Xf");
250 declareCovarianceMatrixKey<double, 2>(wrappers, "2d");
251 declareCovarianceMatrixKey<double, 3>(wrappers, "3d");
252 declareCovarianceMatrixKey<double, 4>(wrappers, "4d");
253 declareCovarianceMatrixKey<double, Eigen::Dynamic>(wrappers, "Xd");
254}
255
256} // namespace table
257} // namespace afw
258} // namespace lsst
lsst::geom::Point< T, 3 > get(BaseRecord const &record) const override
Get a Point from the given record.
Definition aggregates.cc:69
lsst::geom::Point< T, 2 > get(BaseRecord const &record) const override
Get a Point from the given record.
Definition aggregates.cc:44
PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true)
Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() i...
Definition python.h:391
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
Definition python.h:448
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition python.h:242
PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true)
Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() i...
Definition python.h:391
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
Definition python.h:448
void wrapAggregates(WrapperCollection &wrappers)