LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
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"
30 #include "lsst/afw/table/Catalog.h"
31 
32 namespace lsst {
33 namespace afw {
34 namespace table {
35 namespace python {
36 
37 template <typename Record>
38 using PyCatalog = pybind11::class_<CatalogT<Record>, std::shared_ptr<CatalogT<Record>>>;
39 
41 template <typename T, typename Record>
42 ndarray::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.
57 template <typename Record>
58 ndarray::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 
71 template <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 
91 template <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 
110 template <typename T, typename Record>
112  namespace py = pybind11;
113  using namespace pybind11::literals;
114 
115  using Catalog = CatalogT<Record>;
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 
172 template <typename Record>
173 PyCatalog<Record> declareCatalog(utils::python::WrapperCollection &wrappers, std::string const &name,
174  bool isBase = false) {
175  namespace py = pybind11;
176  using namespace pybind11::literals;
177 
178  using Catalog = CatalogT<Record>;
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
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 _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
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