lsst.afw  19.0.0-24-gf0e72354e+1
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,
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 
79 template <typename T, typename Record>
81  namespace py = pybind11;
82  using namespace pybind11::literals;
83 
84  typedef CatalogT<Record> Catalog;
85  typedef typename Field<T>::Value Value;
86 
87  cls.def("isSorted", (bool (Catalog::*)(Key<T> const &) const) & Catalog::isSorted);
88  cls.def("sort", (void (Catalog::*)(Key<T> const &)) & Catalog::sort);
89  cls.def("find", [](Catalog &self, Value const &value, Key<T> const &key) -> std::shared_ptr<Record> {
90  auto iter = self.find(value, key);
91  if (iter == self.end()) {
92  return nullptr;
93  };
94  return iter;
95  });
96  cls.def("upper_bound", [](Catalog &self, Value const &value, Key<T> const &key) -> std::ptrdiff_t {
97  return self.upper_bound(value, key) - self.begin();
98  });
99  cls.def("lower_bound", [](Catalog &self, Value const &value, Key<T> const &key) -> std::ptrdiff_t {
100  return self.lower_bound(value, key) - self.begin();
101  });
102  cls.def("equal_range", [](Catalog &self, Value const &value, Key<T> const &key) {
103  auto p = self.equal_range(value, key);
104  return py::slice(p.first - self.begin(), p.second - self.begin(), 1);
105  });
106  cls.def("between", [](Catalog &self, Value const &lower, Value const &upper, Key<T> const &key) {
107  std::ptrdiff_t a = self.lower_bound(lower, key) - self.begin();
108  std::ptrdiff_t b = self.upper_bound(upper, key) - self.begin();
109  return py::slice(a, b, 1);
110  });
111 
112  cls.def("_getitem_",
113  [](Catalog const &self, Key<T> const &key) { return _getArrayFromCatalog(self, key); });
114 }
115 
129 template <typename Record>
131  bool isBase = false) {
132  namespace py = pybind11;
133  using namespace pybind11::literals;
134 
135  using Catalog = CatalogT<Record>;
136  using Table = typename Record::Table;
137 
138  std::string fullName;
139  if (isBase) {
140  fullName = "_" + name + "CatalogBase";
141  } else {
142  fullName = name + "Catalog";
143  }
144 
145  // We need py::dynamic_attr() in the class definition to support our Python-side caching
146  // of the associated ColumnView.
147  return wrappers.wrapType(
148  PyCatalog<Record>(wrappers.module, fullName.c_str(), py::dynamic_attr()),
149  [](auto &mod, auto &cls) {
150  /* Constructors */
151  cls.def(py::init<Schema const &>(), "schema"_a);
152  cls.def(py::init<std::shared_ptr<Table> const &>(), "table"_a);
153  cls.def(py::init<Catalog const &>(), "other"_a);
154 
155  /* Static Methods */
156  cls.def_static("readFits", (Catalog(*)(std::string const &, int, int)) & Catalog::readFits,
157  "filename"_a, "hdu"_a = fits::DEFAULT_HDU, "flags"_a = 0);
158  cls.def_static("readFits", (Catalog(*)(fits::MemFileManager &, int, int)) & Catalog::readFits,
159  "manager"_a, "hdu"_a = fits::DEFAULT_HDU, "flags"_a = 0);
160  // readFits taking Fits objects not wrapped, because Fits objects are not wrapped.
161 
162  /* Methods */
163  cls.def("getTable", &Catalog::getTable);
164  cls.def_property_readonly("table", &Catalog::getTable);
165  cls.def("getSchema", &Catalog::getSchema);
166  cls.def_property_readonly("schema", &Catalog::getSchema);
167  cls.def("capacity", &Catalog::capacity);
168  cls.def("__len__", &Catalog::size);
169  cls.def("resize", &Catalog::resize);
170 
171  // Use private names for the following so the public Python method
172  // can manage the _column cache
173  cls.def("_getColumnView", &Catalog::getColumnView);
174  cls.def("_addNew", &Catalog::addNew);
175  cls.def("_extend", [](Catalog &self, Catalog const &other, bool deep) {
176  self.insert(self.end(), other.begin(), other.end(), deep);
177  });
178  cls.def("_extend", [](Catalog &self, Catalog const &other, SchemaMapper const &mapper) {
179  self.insert(mapper, self.end(), other.begin(), other.end());
180  });
181  cls.def("_append",
182  [](Catalog &self, std::shared_ptr<Record> const &rec) { self.push_back(rec); });
183  cls.def("_delitem_", [](Catalog &self, std::ptrdiff_t i) {
184  self.erase(self.begin() + utils::python::cppIndex(self.size(), i));
185  });
186  cls.def("_delslice_", [](Catalog &self, py::slice const &s) {
187  Py_ssize_t start = 0, stop = 0, step = 0, length = 0;
188  if (PySlice_GetIndicesEx(s.ptr(), self.size(), &start, &stop, &step, &length) != 0) {
189  throw py::error_already_set();
190  }
191  if (step != 1) {
192  throw py::index_error("Slice step must not exactly 1");
193  }
194  self.erase(self.begin() + start, self.begin() + stop);
195  });
196  cls.def("_clear", &Catalog::clear);
197 
198  cls.def("set", &Catalog::set);
199  cls.def("_getitem_", [](Catalog &self, int i) {
200  return self.get(utils::python::cppIndex(self.size(), i));
201  });
202  cls.def("isContiguous", &Catalog::isContiguous);
203  cls.def("writeFits",
204  (void (Catalog::*)(std::string const &, std::string const &, int) const) &
205  Catalog::writeFits,
206  "filename"_a, "mode"_a = "w", "flags"_a = 0);
207  cls.def("writeFits",
208  (void (Catalog::*)(fits::MemFileManager &, std::string const &, int) const) &
209  Catalog::writeFits,
210  "manager"_a, "mode"_a = "w", "flags"_a = 0);
211  cls.def("reserve", &Catalog::reserve);
212  cls.def("subset",
213  (Catalog(Catalog::*)(ndarray::Array<bool const, 1> const &) const) & Catalog::subset);
214  cls.def("subset",
216  Catalog::subset);
217 
218  declareCatalogOverloads<std::int32_t>(cls);
219  declareCatalogOverloads<std::int64_t>(cls);
220  declareCatalogOverloads<float>(cls);
221  declareCatalogOverloads<double>(cls);
222  declareCatalogOverloads<lsst::geom::Angle>(cls);
223 
224  cls.def("_getitem_",
225  [](Catalog const &self, Key<Flag> const &key) -> ndarray::Array<bool const, 1, 0> {
226  return _getArrayFromCatalog(self, key);
227  });
228 
229  });
230 }
231 
232 } // namespace python
233 } // namespace table
234 } // namespace afw
235 } // namespace lsst
236 
237 #endif // !LSST_AFW_TABLE_PYTHON_CATALOG_H_INCLUDED
lsst::afw::table::CatalogT::end
iterator end()
Definition: Catalog.h:397
std::string
STL class.
std::shared_ptr
STL class.
lsst::afw::table::python::PyCatalog
pybind11::class_< CatalogT< Record >, std::shared_ptr< CatalogT< Record > >> PyCatalog
Definition: catalog.h:38
BaseColumnView.h
lsst::afw::table._base.Catalog
Definition: _base.py:88
lsst::utils::python::cppIndex
std::size_t cppIndex(std::ptrdiff_t size, std::ptrdiff_t i)
lsst::afw::fits::MemFileManager
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:121
lsst::afw::geom.transform.transformContinued.name
string name
Definition: transformContinued.py:32
lsst::afw::table::python::_getArrayFromCatalog
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
end
int end
Definition: BoundedField.cc:105
lsst::afw::geom.transform.transformContinued.cls
cls
Definition: transformContinued.py:33
lsst::afw::table::python::declareCatalog
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:130
lsst::afw::table::CatalogT::size
size_type size() const
Return the number of elements in the catalog.
Definition: Catalog.h:408
lsst::afw::table._base.Catalog.clear
def clear(self)
Definition: _base.py:161
lsst::utils::python::WrapperCollection::wrapType
PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true)
set
daf::base::PropertySet * set
Definition: fits.cc:912
std::string::c_str
T c_str(T... args)
other
ItemVariant const * other
Definition: Schema.cc:56
step
int const step
Definition: BoundedField.cc:102
lsst::afw::table::SchemaMapper
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
lsst::afw::table::Key
A class used as a handle to a particular field in a table.
Definition: fwd.h:45
lsst::utils::python::WrapperCollection
b
table::Key< int > b
Definition: TransmissionCurve.cc:467
lsst
A base class for image defects.
a
table::Key< int > a
Definition: TransmissionCurve.cc:466
key
Key< U > key
Definition: Schema.cc:281
pybind11
std::ptrdiff_t
mapper
SchemaMapper * mapper
Definition: SchemaMapper.cc:78
lsst::afw::table::FieldBase::Value
T Value
the type returned by BaseRecord::get
Definition: FieldBase.h:44
lsst::utils::python::WrapperCollection::module
pybind11::module module
Catalog.h
lsst::afw::table::CatalogT::begin
iterator begin()
Iterator access.
Definition: Catalog.h:396
length
def length(self)
python.h
lsst::afw::table::CatalogT
A custom container class for records, based on std::vector.
Definition: Catalog.h:97
iter
def iter(self)
lsst::afw::table::python::declareCatalogOverloads
void declareCatalogOverloads(PyCatalog< Record > &cls)
Declare field-type-specific overloaded catalog member functions for one field type.
Definition: catalog.h:80
lsst::afw::table::Key< Flag >
Key specialization for Flag.
Definition: Flag.h:94