lsst.meas.extensions.astrometryNet  14.0-1-g013352c+31
astrometry_net.cc
Go to the documentation of this file.
1 // -*- lsst-C++ -*-
2 
3 #include <sstream>
4 #include <utility>
5 #include <vector>
6 
7 #include "lsst/pex/exceptions.h"
9 
10 namespace lsst {
11 namespace meas {
12 namespace extensions {
13 namespace astrometryNet {
14 
15 namespace {
16 
17 struct timer_baton {
18  solver_t* s;
19  double timelimit;
20 };
21 
22 static time_t timer_callback(void* baton) {
23  struct timer_baton* tt = static_cast<struct timer_baton*>(baton);
24  solver_t* solver = tt->s;
25  if (solver->timeused > tt->timelimit)
26  solver->quit_now = 1;
27  return 1;
28 }
29 
30 } // namespace <anonymous>
31 
32 MultiIndex::MultiIndex(std::string const & filepath) : _multiindex(multiindex_new(filepath.c_str())) {
33  if (!_multiindex) {
35  os << "Could not read multi-index star file " << filepath;
37  }
38 }
39 
40 void MultiIndex::addIndex(std::string const & filepath, bool metadataOnly) {
41  int const flags = metadataOnly ? INDEX_ONLY_LOAD_METADATA : 0;
42  if (multiindex_add_index(_multiindex.get(), filepath.c_str(), flags)) {
44  os << "Failed to read multiindex from \"" << filepath << "\""
45  << " with meatadaOnly=" << metadataOnly;
47  }
48 }
49 
50 int MultiIndex::isWithinRange(double ra, double dec, double radius_deg) {
51  return index_is_within_range(multiindex_get(_multiindex.get(), 0), ra, dec, radius_deg);
52 }
53 
55  if (multiindex_reload_starkd(_multiindex.get())) {
57  os << "Failed to reload multi-index star file " << getName();
59  }
60 }
61 
62 
63 Solver::Solver() : _solver(solver_new()) {}
64 
66  // Working around a bug in Astrometry.net: doesn't take ownership of the field.
67  // unseemly familiarity with the innards... but valgrind-clean.
68  starxy_free(_solver->fieldxy);
69  _solver->fieldxy = NULL;
70 }
71 
74  lsst::afw::coord::Coord const &ctrCoord,
75  lsst::afw::geom::Angle const &radius,
76  const char* idCol,
77  std::vector<std::string> const& filterNameList,
78  std::vector<std::string> const& magColList,
79  std::vector<std::string> const& magErrColList,
80  const char* starGalCol,
81  const char* varCol,
82  bool uniqueIds)
83 {
84  if ((filterNameList.size() != magColList.size()) || (filterNameList.size() != magErrColList.size())) {
86  "Filter name, mag column, and mag error column vectors must be the same length.");
87  }
88  std::vector<detail::MagColInfo> magColInfoList;
89  for (size_t i=0; i<filterNameList.size(); ++i) {
91  mc.filterName = filterNameList[i];
92  mc.magCol = magColList[i];
93  mc.magErrCol = magErrColList[i];
94  magColInfoList.push_back(mc);
95  }
96  return detail::getCatalogImpl(inds, ctrCoord, radius,
97  idCol, magColInfoList, starGalCol, varCol, uniqueIds);
98 }
99 
101  // Gather solve stats...
102  auto qa = std::make_shared<daf::base::PropertyList>();
103  // FIXME -- Ticket #1875 prevents dotted-names from working with toString().
104  qa->set("meas_astrom*an*n_tried", _solver->numtries);
105  qa->set("meas_astrom*an*n_matched", _solver->nummatches);
106  qa->set("meas_astrom*an*n_scaleok", _solver->numscaleok);
107  qa->set("meas_astrom*an*n_cxdxcut", _solver->num_cxdx_skipped);
108  qa->set("meas_astrom*an*n_meanxcut", _solver->num_meanx_skipped);
109  qa->set("meas_astrom*an*n_radeccut", _solver->num_radec_skipped);
110  qa->set("meas_astrom*an*n_scalecut", _solver->num_abscale_skipped);
111  qa->set("meas_astrom*an*n_verified", _solver->num_verified);
112  qa->set("meas_astrom*an*time_used", _solver->timeused);
113  qa->set("meas_astrom*an*best_logodds", _solver->best_logodds);
114  if (_solver->best_index) {
115  index_t* ind = _solver->best_index;
116  qa->set("meas_astrom*an*best_index*id", ind->indexid);
117  qa->set("meas_astrom*an*best_index*hp", ind->healpix);
118  qa->set("meas_astrom*an*best_index*nside", ind->hpnside);
119  qa->set("meas_astrom*an*best_index*name", std::string(ind->indexname));
120  }
121  if (_solver->have_best_match) {
122  MatchObj* mo = &(_solver->best_match);
123  std::string s = boost::str(boost::format("%i") % mo->star[0]);
124  for (int i=1; i<mo->dimquads; i++)
125  s = s + boost::str(boost::format(", %i") % mo->star[i]);
126  qa->set("meas_astrom*an*best_match*starinds", s);
127  qa->set("meas_astrom*an*best_match*coderr", std::sqrt(mo->code_err));
128  qa->set("meas_astrom*an*best_match*nmatch", mo->nmatch);
129  qa->set("meas_astrom*an*best_match*ndistract", mo->ndistractor);
130  qa->set("meas_astrom*an*best_match*nconflict", mo->nconflict);
131  qa->set("meas_astrom*an*best_match*nfield", mo->nfield);
132  qa->set("meas_astrom*an*best_match*nindex", mo->nindex);
133  qa->set("meas_astrom*an*best_match*nbest", mo->nbest);
134  qa->set("meas_astrom*an*best_match*logodds", mo->logodds);
135  qa->set("meas_astrom*an*best_match*parity", mo->parity ? 0 : 1);
136  qa->set("meas_astrom*an*best_match*nobjs", mo->objs_tried);
137  }
138  return qa;
139 }
140 
142  MatchObj* match = solver_get_best_match(_solver.get());
143  if (!match)
145  tan_t* wcs = &(match->wcstan);
146 
147  afw::geom::Point2D crpix(wcs->crpix[0], wcs->crpix[1]);
149  (new afw::coord::Coord(wcs->crval[0] * afw::geom::degrees,
150  wcs->crval[1] * afw::geom::degrees));
151  return afw::image::makeWcs(*crval, crpix,
152  wcs->cd[0][0], wcs->cd[0][1],
153  wcs->cd[1][0], wcs->cd[1][1]);
154 }
155 
156 void Solver::run(double cpulimit) {
157  solver_log_params(_solver.get());
158  struct timer_baton tt;
159  if (cpulimit > 0.) {
160  tt.s = _solver.get();
161  tt.timelimit = cpulimit;
162  _solver->userdata = &tt;
163  _solver->timer_callback = timer_callback;
164  }
165  solver_run(_solver.get());
166  if (cpulimit > 0.) {
167  _solver->timer_callback = NULL;
168  _solver->userdata = NULL;
169  }
170 }
171 
179  for (std::vector<index_t*>::iterator pind = inds.begin();
180  pind != inds.end(); ++pind) {
181  detail::IndexManager man(*pind);
182 // printf("Checking index \"%s\"\n", man.index->indexname);
183  if (_solver->use_radec) {
184  double ra,dec,radius;
185  xyzarr2radecdeg(_solver->centerxyz, &ra, &dec);
186  radius = distsq2deg(_solver->r2);
187  if (!index_is_within_range(man.index, ra, dec, radius)) {
188  //printf("Not within RA,Dec range\n");
189  continue;
190  }
191  }
192  // qlo,qhi in arcsec
193  double qlo, qhi;
194  solver_get_quad_size_range_arcsec(_solver.get(), &qlo, &qhi);
195  if (!index_overlaps_scale_range(man.index, qlo, qhi)) {
196 // printf("Not within quad scale range\n");
197  continue;
198  }
199 // printf("Adding index.\n");
200  if (index_reload(man.index)) {
202  "Failed to index_reload() an astrometry_net_data index file -- out of file descriptors?");
203  }
204 
205  solver_add_index(_solver.get(), man.index);
206  }
207 }
208 
209 void Solver::setImageSize(int width, int height) {
210  solver_set_field_bounds(_solver.get(), 0, width, 0, height);
211  double hi = hypot(width, height);
212  double lo = 0.1 * std::min(width, height);
213  solver_set_quad_size_range(_solver.get(), lo, hi);
214 }
215 
216 void Solver::setStars(lsst::afw::table::SourceCatalog const & srcs, int x0, int y0) {
217  // convert to Astrometry.net "starxy_t"
218  starxy_free(_solver->fieldxy);
219  const size_t N = srcs.size();
220  starxy_t *starxy = starxy_new(N, true, false);
221  for (size_t i=0; i<N; ++i) {
222  double const x = srcs[i].getX();
223  double const y = srcs[i].getY();
224  double const flux = srcs[i].getPsfFlux();
225  starxy_set(starxy, i, x - x0, y - y0);
226  starxy_set_flux(starxy, i, flux);
227  }
228  // Sort the array
229  starxy_sort_by_flux(starxy);
230 
231  starxy_free(solver_get_field(_solver.get()));
232  solver_free_field(_solver.get());
233  solver_set_field(_solver.get(), starxy);
234  solver_reset_field_size(_solver.get());
235  // Find field boundaries and precompute kdtree
236  solver_preprocess_field(_solver.get());
237 }
238 
239 
241  lsst::afw::coord::IcrsCoord icrs = coord.toIcrs();
242  return lsst::afw::geom::Angle(healpix_distance_to_radec(hp, nside, icrs.getLongitude().asDegrees(),
243  icrs.getLatitude().asDegrees(), NULL),
245 }
246 
247 }}}} // namespace lsst::meas::extensions::astrometryNet
std::string magCol
name of magnitude column
Definition: utils.h:19
lsst::afw::table::SimpleCatalog getCatalogImpl(std::vector< index_t *> inds, lsst::afw::coord::Coord const &ctrCoord, lsst::afw::geom::Angle const &radius, const char *idCol, std::vector< MagColInfo > const &magColInfoList, const char *starGalCol, const char *varCol, bool uniqueIds=true)
Implementation for index_t::getCatalog method.
Definition: utils.cc:59
solver_t * s
lsst::afw::geom::Angle getLongitude() const
std::string magErrCol
name of magnitude sigma column
Definition: utils.h:20
AngleUnit constexpr degrees
std::shared_ptr< Wcs > makeWcs(std::shared_ptr< lsst::daf::base::PropertySet > const &fitsMetadata, bool stripMetadata=false)
MultiIndex(std::string const &filepath)
Construct a MultiIndex from an astrometry.net multi-index file.
table::PointKey< double > crval
virtual IcrsCoord toIcrs() const
T end(T... args)
lsst::afw::geom::Angle getLatitude() const
STL class.
T min(T... args)
double timelimit
T push_back(T... args)
RAII manager for astrometry.net indices.
Definition: utils.h:32
T str(T... args)
double x
std::shared_ptr< lsst::daf::base::PropertyList > getSolveStats() const
T get(T... args)
T size(T... args)
#define LSST_EXCEPT(type,...)
STL class.
T begin(T... args)
void addIndex(std::string const &filepath, bool metadataOnly)
Add an index read from a file.
T c_str(T... args)
T sqrt(T... args)
lsst::afw::geom::Angle healpixDistance(int hp, int nside, lsst::afw::coord::Coord const &coord)
Calculate the distance from coordinates to a healpix.
std::shared_ptr< lsst::afw::image::Wcs > getWcs()
constexpr double asDegrees() const noexcept
void setStars(lsst::afw::table::SourceCatalog const &srcs, int x0, int y0)
lsst::afw::table::SimpleCatalog getCatalog(std::vector< index_t *> inds, lsst::afw::coord::Coord const &ctrCoord, lsst::afw::geom::Angle const &radius, const char *idCol, std::vector< std::string > const &filterNameList, std::vector< std::string > const &magColList, std::vector< std::string > const &magErrColList, const char *starGalCol, const char *varCol, bool uniqueIds=true)
Load reference objects in a region of the sky described by a center coordinate and a radius...
int isWithinRange(double ra, double dec, double radius_deg)
Is this multi-index in range of the specified cone?
void addIndices(std::vector< index_t *> inds)
Add indices to the solver.
table::PointKey< double > crpix