LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
catalog.h
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#ifndef AFW_TABLE_PYTHON_CATALOG_H_INCLUDED
24#define AFW_TABLE_PYTHON_CATALOG_H_INCLUDED
25
26#include "pybind11/pybind11.h"
27
28#include "lsst/utils/python.h"
31
32namespace lsst {
33namespace afw {
34namespace table {
35namespace python {
36
37template <typename Record>
38using PyCatalog = pybind11::class_<CatalogT<Record>, std::shared_ptr<CatalogT<Record>>>;
39
41template <typename T, typename Record>
42ndarray::Array<typename Field<T>::Value const, 1, 1> _getArrayFromCatalog(
43 CatalogT<Record> const &catalog,
44 Key<T> const &key
45) {
46 ndarray::Array<typename Field<T>::Value, 1, 1> out = ndarray::allocate(catalog.size());
47 auto outIter = out.begin();
48 auto inIter = catalog.begin();
49 for (; inIter != catalog.end(); ++inIter, ++outIter) {
50 *outIter = inIter->get(key);
51 }
52 return out;
53}
54
55// Specialization of the above for lsst::geom::Angle: have to return a double array (in
56// radians), since NumPy arrays can't hold lsst::geom::Angles.
57template <typename Record>
58ndarray::Array<double const, 1, 1> _getArrayFromCatalog(
59 CatalogT<Record> const &catalog,
60 Key<lsst::geom::Angle> const &key
61) {
62 ndarray::Array<double, 1, 1> out = ndarray::allocate(catalog.size());
63 auto outIter = out.begin();
64 auto inIter = catalog.begin();
65 for (; inIter != catalog.end(); ++inIter, ++outIter) {
66 *outIter = inIter->get(key).asRadians();
67 }
68 return out;
69}
70
71template <typename Record>
73 CatalogT<Record> & catalog,
74 Key<Flag> const & key,
75 ndarray::Array<bool const, 1> const & array
76) {
77 if (array.size() != catalog.size()) {
78 throw LSST_EXCEPT(
80 (boost::format("Catalog has %d rows, while array has %d elements.")
81 % catalog.size() % array.size()).str()
82 );
83 }
84 auto catIter = catalog.begin();
85 auto arrayIter = array.begin();
86 for (; catIter != catalog.end(); ++catIter, ++arrayIter) {
87 catIter->set(key, *arrayIter);
88 }
89}
90
91template <typename Record>
93 CatalogT<Record> & catalog,
94 Key<Flag> const & key,
95 bool value
96) {
97 for (auto catIter = catalog.begin(); catIter != catalog.end(); ++catIter) {
98 catIter->set(key, value);
99 }
100}
101
110template <typename T, typename Record>
112 namespace py = pybind11;
113 using namespace pybind11::literals;
114
116 using Value = typename Field<T>::Value;
117
118 cls.def("isSorted", (bool (Catalog::*)(Key<T> const &) const) & Catalog::isSorted);
119 cls.def("sort", (void (Catalog::*)(Key<T> const &)) & Catalog::sort);
120 cls.def("find", [](Catalog &self, Value const &value, Key<T> const &key) -> std::shared_ptr<Record> {
121 auto iter = self.find(value, key);
122 if (iter == self.end()) {
123 return nullptr;
124 };
125 return iter;
126 });
127 cls.def("upper_bound", [](Catalog &self, Value const &value, Key<T> const &key) -> std::ptrdiff_t {
128 return self.upper_bound(value, key) - self.begin();
129 });
130 cls.def("lower_bound", [](Catalog &self, Value const &value, Key<T> const &key) -> std::ptrdiff_t {
131 return self.lower_bound(value, key) - self.begin();
132 });
133 cls.def("equal_range", [](Catalog &self, Value const &value, Key<T> const &key) {
134 auto p = self.equal_range(value, key);
135 return py::slice(p.first - self.begin(), p.second - self.begin(), 1);
136 });
137 cls.def("between", [](Catalog &self, Value const &lower, Value const &upper, Key<T> const &key) {
138 std::ptrdiff_t a = self.lower_bound(lower, key) - self.begin();
139 std::ptrdiff_t b = self.upper_bound(upper, key) - self.begin();
140 return py::slice(a, b, 1);
141 });
142
143 cls.def("_getitem_",
144 [](Catalog const &self, Key<T> const &key) { return _getArrayFromCatalog(self, key); });
145 cls.def(
146 "_set_flag",
147 [](Catalog &self, Key<Flag> const & key, ndarray::Array<bool const, 1> const & array) {
148 _setFlagColumnToArray(self, key, array);
149 }
150 );
151 cls.def(
152 "_set_flag",
153 [](Catalog &self, Key<Flag> const & key, bool value) {
154 _setFlagColumnToScalar(self, key, value);
155 }
156 );
157}
158
172template <typename Record>
173PyCatalog<Record> declareCatalog(utils::python::WrapperCollection &wrappers, std::string const &name,
174 bool isBase = false) {
175 namespace py = pybind11;
176 using namespace pybind11::literals;
177
179 using Table = typename Record::Table;
180
181 std::string fullName;
182 if (isBase) {
183 fullName = "_" + name + "CatalogBase";
184 } else {
185 fullName = name + "Catalog";
186 }
187
188 // We need py::dynamic_attr() in the class definition to support our Python-side caching
189 // of the associated ColumnView.
190 return wrappers.wrapType(
191 PyCatalog<Record>(wrappers.module, fullName.c_str(), py::dynamic_attr()),
192 [](auto &mod, auto &cls) {
193 /* Constructors */
194 cls.def(py::init<Schema const &>(), "schema"_a);
195 cls.def(py::init<std::shared_ptr<Table> const &>(), "table"_a);
196 cls.def(py::init<Catalog const &>(), "other"_a);
197
198 /* Static Methods */
199 cls.def_static("readFits", (Catalog(*)(std::string const &, int, int)) & Catalog::readFits,
200 "filename"_a, "hdu"_a = fits::DEFAULT_HDU, "flags"_a = 0);
201 cls.def_static("readFits", (Catalog(*)(fits::MemFileManager &, int, int)) & Catalog::readFits,
202 "manager"_a, "hdu"_a = fits::DEFAULT_HDU, "flags"_a = 0);
203 // readFits taking Fits objects not wrapped, because Fits objects are not wrapped.
204
205 /* Methods */
206 cls.def("getTable", &Catalog::getTable);
207 cls.def_property_readonly("table", &Catalog::getTable);
208 cls.def("getSchema", &Catalog::getSchema);
209 cls.def_property_readonly("schema", &Catalog::getSchema);
210 cls.def("capacity", &Catalog::capacity);
211 cls.def("__len__", &Catalog::size);
212 cls.def("resize", &Catalog::resize);
213
214 // Use private names for the following so the public Python method
215 // can manage the _column cache
216 cls.def("_getColumnView", &Catalog::getColumnView);
217 cls.def("_addNew", &Catalog::addNew);
218 cls.def("_extend", [](Catalog &self, Catalog const &other, bool deep) {
219 self.insert(self.end(), other.begin(), other.end(), deep);
220 });
221 cls.def("_extend", [](Catalog &self, Catalog const &other, SchemaMapper const &mapper) {
222 self.insert(mapper, self.end(), other.begin(), other.end());
223 });
224 cls.def("_append",
225 [](Catalog &self, std::shared_ptr<Record> const &rec) { self.push_back(rec); });
226 cls.def("_delitem_", [](Catalog &self, std::ptrdiff_t i) {
227 self.erase(self.begin() + utils::python::cppIndex(self.size(), i));
228 });
229 cls.def("_delslice_", [](Catalog &self, py::slice const &s) {
230 Py_ssize_t start = 0, stop = 0, step = 0, length = 0;
231 if (PySlice_GetIndicesEx(s.ptr(), self.size(), &start, &stop, &step, &length) != 0) {
232 throw py::error_already_set();
233 }
234 if (step != 1) {
235 throw py::index_error("Slice step must not exactly 1");
236 }
237 self.erase(self.begin() + start, self.begin() + stop);
238 });
239 cls.def("_clear", &Catalog::clear);
240
241 cls.def("set", &Catalog::set);
242 cls.def("_getitem_", [](Catalog &self, int i) {
243 return self.get(utils::python::cppIndex(self.size(), i));
244 });
245 cls.def("isContiguous", &Catalog::isContiguous);
246 cls.def("writeFits",
247 (void (Catalog::*)(std::string const &, std::string const &, int) const) &
249 "filename"_a, "mode"_a = "w", "flags"_a = 0);
250 cls.def("writeFits",
251 (void (Catalog::*)(fits::MemFileManager &, std::string const &, int) const) &
253 "manager"_a, "mode"_a = "w", "flags"_a = 0);
254 cls.def("reserve", &Catalog::reserve);
255 cls.def("subset",
256 (Catalog(Catalog::*)(ndarray::Array<bool const, 1> const &) const) & Catalog::subset);
257 cls.def("subset",
259 Catalog::subset);
260
261 declareCatalogOverloads<std::int32_t>(cls);
262 declareCatalogOverloads<std::int64_t>(cls);
263 declareCatalogOverloads<float>(cls);
264 declareCatalogOverloads<double>(cls);
265 declareCatalogOverloads<lsst::geom::Angle>(cls);
266
267 cls.def("_getitem_",
268 [](Catalog const &self, Key<Flag> const &key) -> ndarray::Array<bool const, 1, 0> {
269 return _getArrayFromCatalog(self, key);
270 });
271
272 });
273}
274
275} // namespace python
276} // namespace table
277} // namespace afw
278} // namespace lsst
279
280#endif // !LSST_AFW_TABLE_PYTHON_CATALOG_H_INCLUDED
table::Key< std::string > name
Definition: Amplifier.cc:116
int const step
int end
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
SchemaMapper * mapper
Definition: SchemaMapper.cc:71
table::Key< int > b
table::Key< int > a
T c_str(T... args)
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:121
A custom container class for records, based on std::vector.
Definition: Catalog.h:98
size_type size() const
Return the number of elements in the catalog.
Definition: Catalog.h:413
iterator begin()
Iterator access.
Definition: Catalog.h:401
Key specialization for Flag.
Definition: Flag.h:94
A class used as a handle to a particular field in a table.
Definition: Key.h:53
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
Reports attempts to exceed implementation-defined length limits for some classes.
Definition: Runtime.h:76
daf::base::PropertySet * set
Definition: fits.cc:912
void _setFlagColumnToArray(CatalogT< Record > &catalog, Key< Flag > const &key, ndarray::Array< bool const, 1 > const &array)
Definition: catalog.h:72
ndarray::Array< typename Field< T >::Value const, 1, 1 > _getArrayFromCatalog(CatalogT< Record > const &catalog, Key< T > const &key)
Extract a column from a potentially non-contiguous Catalog.
Definition: catalog.h:42
void _setFlagColumnToScalar(CatalogT< Record > &catalog, Key< Flag > const &key, bool value)
Definition: catalog.h:92
pybind11::class_< CatalogT< Record >, std::shared_ptr< CatalogT< Record > > > PyCatalog
Definition: catalog.h:38
PyCatalog< Record > declareCatalog(utils::python::WrapperCollection &wrappers, std::string const &name, bool isBase=false)
Wrap an instantiation of lsst::afw::table::CatalogT<Record>.
Definition: catalog.h:173
void declareCatalogOverloads(PyCatalog< Record > &cls)
Declare field-type-specific overloaded catalog member functions for one field type.
Definition: catalog.h:111
std::size_t cppIndex(std::ptrdiff_t size, std::ptrdiff_t i)
Compute a C++ index from a Python index (negative values count from the end) and range-check.
Definition: python.h:124
def writeFits(filename, stamps, metadata, type_name, write_mask, write_variance, write_archive=False)
Definition: stamps.py:42
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
T Value
the type returned by BaseRecord::get
Definition: FieldBase.h:42