56LOG_LOGGER _log =
LOG_GET(
"lsst.jointcal.Associations");
78 centers.
push_back(ccdImage->getBoresightRaDec());
86 _commonTangentPoint =
Point(commonTangentPoint.getX(), commonTangentPoint.getY());
87 for (
auto &ccdImage :
ccdImageList) ccdImage->setCommonTangentPoint(_commonTangentPoint);
92 Frame tangentPlaneFrame;
95 Frame CTPFrame = ccdImage->getPixelToCommonTangentPlane()->apply(ccdImage->getImageFrame(),
false);
96 if (tangentPlaneFrame.
getArea() == 0)
97 tangentPlaneFrame = CTPFrame;
99 tangentPlaneFrame += CTPFrame;
104 TanPixelToRaDec commonTangentPlaneToRaDec(identity, _commonTangentPoint);
105 Frame raDecFrame = commonTangentPlaneToRaDec.
apply(tangentPlaneFrame,
false);
111 LOGLS_INFO(_log,
"Computed tangent plane box for data (degrees): " << raDecFrame);
121 const bool enlargeFittedList) {
127 item->clearBeforeAssoc();
137 ccdImage->resetCatalogForFit();
143 Frame ccdImageFrameCPT = toCommonTangentPlane->apply(ccdImage->getImageFrame(),
false);
144 ccdImageFrameCPT = ccdImageFrameCPT.
rescale(1.10);
150 if (ccdImageFrameCPT.
inFrame(*fittedStar)) {
157 toCommonTangentPlane.
get(), matchCutInArcSec / 3600.);
160 LOGLS_DEBUG(_log,
"Measured-to-Fitted matches before removing ambiguities " << starMatchList->size());
161 starMatchList->removeAmbiguities(*toCommonTangentPlane);
162 LOGLS_DEBUG(_log,
"Measured-to-Fitted matches after removing ambiguities " << starMatchList->size());
166 int matchedCount = 0;
167 for (
auto const &starMatch : *starMatchList) {
168 auto bs = starMatch.s1;
169 auto ms_const = std::dynamic_pointer_cast<const MeasuredStar>(bs);
170 auto ms = std::const_pointer_cast<MeasuredStar>(ms_const);
171 auto bs2 = starMatch.s2;
172 auto fs_const = std::dynamic_pointer_cast<const FittedStar>(bs2);
173 auto fs = std::const_pointer_cast<FittedStar>(fs_const);
174 ms->setFittedStar(fs);
177 LOGLS_DEBUG(_log,
"Matched " << matchedCount <<
" objects in " << ccdImage->getName());
180 int unMatchedCount = 0;
181 for (
auto const &mstar : catalog) {
183 if (mstar->getFittedStar())
continue;
184 if (enlargeFittedList) {
185 auto fs = std::make_shared<FittedStar>(*mstar);
187 toCommonTangentPlane->transformPosAndErrors(*fs, *fs);
189 mstar->setFittedStar(fs);
193 LOGLS_DEBUG(_log,
"Unmatched objects: " << unMatchedCount);
205 std::string const &fluxField,
float refCoordinateErr,
206 bool rejectBadFluxes) {
207 if (refCat.
size() == 0) {
209 " reference catalog is empty : stop here "));
217 raErrKey = refCat.
getSchema()[
"coord_raErr"];
218 decErrKey = refCat.
getSchema()[
"coord_decErr"];
221 auto fluxKey = refCat.
getSchema().
find<
double>(fluxField).key;
225 fluxErrKey = refCat.
getSchema().
find<
double>(fluxField +
"Err").key;
228 << fluxField <<
"Err"
229 <<
") not found in reference catalog. Not using ref flux errors.");
239 LOGLS_WARN(_log,
"Not loading proper motions: (pm_ra,pm_dec) fields not found in reference catalog.");
241 LOGLS_WARN(_log,
"Not loading proper motions: RA/Dec proper motion values must be `geom:Angle`: "
246 pmDecErrKey = refCat.
getSchema().
find<
float>(
"pm_decErr").key;
248 LOGLS_WARN(_log,
"Not loading proper motions: error fields not available: " << ex.
what());
253 pmRaDecCovKey = refCat.
getSchema().
find<
float>(
"pm_ra_Dec_Cov").key;
255 LOGLS_WARN(_log,
"No ra/dec proper motion covariances in refcat: " << ex.
what());
259 for (
size_t i = 0; i < refCat.
size(); i++) {
260 auto const &record = refCat.
get(i);
262 auto coord = record->get(coordKey);
263 double flux = record->get(fluxKey);
265 if (fluxErrKey.isValid()) {
266 fluxErr = record->get(fluxErrKey);
272 auto star = std::make_shared<RefStar>(ra,
dec, flux, fluxErr);
280 star->vx =
std::pow(refCoordinateErr / 1000. / 3600. /
std::cos(coord.getLatitude()), 2);
281 star->vy =
std::pow(refCoordinateErr / 1000. / 3600., 2);
286 star->setProperMotion(std::make_unique<ProperMotion const>(
287 record->get(pmRaKey).asRadians(), record->get(pmDecKey).asRadians(),
288 record->get(pmRaErrKey), record->get(pmDecErrKey), record->get(pmRaDecCovKey)));
290 star->setProperMotion(std::make_unique<ProperMotion const>(
291 record->get(pmRaKey).asRadians(), record->get(pmDecKey).asRadians(),
292 record->get(pmRaErrKey), record->get(pmDecErrKey)));
306 TanRaDecToPixel raDecToCommonTangentPlane(identity, _commonTangentPoint);
308 associateRefStars(matchCut.
asArcseconds(), &raDecToCommonTangentPlane);
311void Associations::associateRefStars(
double matchCutInArcSec,
const AstrometryTransform *transform) {
315 matchCutInArcSec / 3600.);
317 LOGLS_DEBUG(_log,
"Refcat matches before removing ambiguities " << starMatchList->size());
318 starMatchList->removeAmbiguities(*transform);
319 LOGLS_DEBUG(_log,
"Refcat matches after removing ambiguities " << starMatchList->size());
322 for (
auto const &starMatch : *starMatchList) {
324 const auto &rs_const =
dynamic_cast<const RefStar &
>(bs);
325 auto &rs =
const_cast<RefStar &
>(rs_const);
326 const BaseStar &bs2 = *starMatch.s2;
327 const auto &fs_const =
dynamic_cast<const FittedStar &
>(bs2);
328 auto &fs =
const_cast<FittedStar &
>(fs_const);
334 "Associated " << starMatchList->size() <<
" reference stars among " <<
refStarList.
size());
338 selectFittedStars(minMeasurements);
339 normalizeFittedStars();
342void Associations::selectFittedStars(
int minMeasurements) {
345 int totalMeasured = 0, validMeasured = 0;
351 for (
auto mi = catalog.
begin(); mi != catalog.
end();) {
357 if (fittedStar ==
nullptr) {
364 if (!fittedStar->getRefStar() && fittedStar->getMeasurementCount() < minMeasurements) {
365 fittedStar->getMeasurementCount()--;
366 mi = catalog.
erase(mi);
376 if ((*fi)->getMeasurementCount() == 0) {
384 LOGLS_INFO(_log,
"Total, valid number of Measured stars: " << totalMeasured <<
", " << validMeasured);
387void Associations::normalizeFittedStars() {
392 fittedStar->setFlux(0.0);
393 fittedStar->getMag() = 0.0;
399 MeasuredStarList &catalog = ccdImage->getCatalogForFit();
400 for (
auto &mi : catalog) {
401 auto fittedStar = mi->getFittedStar();
402 if (fittedStar ==
nullptr)
404 pex::exceptions::RuntimeError,
405 "All measuredStars must have a fittedStar: did you call selectFittedStars()?"));
406 auto point = toCommonTangentPlane->apply(*mi);
407 fittedStar->x += point.x;
408 fittedStar->y += point.y;
409 fittedStar->getFlux() += mi->getFlux();
413 _maxMeasuredStars = 0;
415 auto measurementCount = fi->getMeasurementCount();
416 _maxMeasuredStars += measurementCount;
417 fi->x /= measurementCount;
418 fi->y /= measurementCount;
419 fi->getFlux() /= measurementCount;
420 fi->getMag() = utils::nanojanskyToABMagnitude(fi->getFlux());
429 auto fittedStar = *
iter;
430 if (fittedStar->getMeasurementCount() == 0) {
431 LOGLS_TRACE(_log,
"Deleting FittedStar (has no measuredStars): " << *fittedStar);
439 LOGLS_INFO(_log,
"Removed " <<
count <<
" fittedStars that had no associated measuredStar.");
443void Associations::assignMags() {
446 for (
auto const &mstar : catalog) {
448 if (!fstar)
continue;
459 "DeprojectFittedStars: Fitted stars are already in sidereal coordinates, nothing done ");
470 return item->getCatalogForFit().size() > 0;
477 if ((fittedStar !=
nullptr) && (fittedStar->getRefStar() !=
nullptr))
count++;
483void Associations::collectMCStars(
int realization) {
489 string dbimdir = ccdImage.Dir();
490 string mctruth = dbimdir +
"/mc/mctruth.list";
492 if (realization >= 0) {
494 sstrm << dbimdir <<
"/mc/mctruth_" << realization <<
".list";
495 mctruth = sstrm.
str();
498 AstrometryTransformIdentity gti;
502 DicStarList mctruthlist(mctruth);
506 for (smI = starMatchList->begin(); smI != starMatchList->end(); smI++) {
507 StarMatch &sm = *smI;
508 BaseStar *bs = sm.s1;
509 MeasuredStar *mstar =
dynamic_cast<MeasuredStar *
>(bs);
511 DicStar *dstar =
dynamic_cast<DicStar *
>(bs);
513 mcstar->GetMCInfo().iflux = dstar->getval(
"iflux");
514 mcstar->GetMCInfo().tflux = dstar->getval(
"sflux");
521 LOGLS_FATAL(_log,
"CollectMCStars Unable to match MCTruth w/ catalog!");
table::Key< int > detector
#define LSST_EXCEPT(type,...)
Combinatorial searches for linear transformations to go from list1 to list2.
#define LOGLS_WARN(logger, message)
#define LOGLS_FATAL(logger, message)
#define LOGLS_INFO(logger, message)
#define LOGLS_DEBUG(logger, message)
#define LOGLS_TRACE(logger, message)
table::Key< table::Array< std::uint8_t > > wcs
std::shared_ptr< RecordT > const get(size_type i) const
bool isValid() const noexcept
SchemaItem< T > find(std::string const &name) const
constexpr double asArcseconds() const noexcept
size_t nFittedStarsWithAssociatedRefStar() const
Return the number of fittedStars that have an associated refStar.
void cleanFittedStars()
Remove FittedStars that have no measured stars; this can happen after outlier rejection.
void computeCommonTangentPoint()
Sets a shared tangent point for all ccdImages, using the mean of the centers of all ccdImages.
lsst::sphgeom::Circle computeBoundingCircle() const
Return the bounding circle in on-sky (RA, Dec) coordinates containing all CcdImages.
int nCcdImagesValidForFit() const
return the number of CcdImages with non-empty catalogs to-be-fit.
void createCcdImage(afw::table::SourceCatalog &catalog, const std::shared_ptr< lsst::afw::geom::SkyWcs > &wcs, const std::shared_ptr< lsst::afw::image::VisitInfo > &visitInfo, const lsst::geom::Box2I &bbox, const std::string &filter, const std::shared_ptr< afw::image::PhotoCalib > &photoCalib, const std::shared_ptr< afw::cameraGeom::Detector > &detector, int visit, int ccd, const lsst::jointcal::JointcalControl &control)
Create a ccdImage from an exposure catalog and metadata, and add it to the list.
void associateCatalogs(double matchCutInArcsec=0, bool useFittedList=false, bool enlargeFittedList=true)
incrementaly builds a merged catalog of all image catalogs
void setCommonTangentPoint(lsst::geom::Point2D const &commonTangentPoint)
Shared tangent point for all ccdImages (decimal degrees).
Point getCommonTangentPoint() const
Shared tangent point for all ccdImages (decimal degrees).
void collectRefStars(afw::table::SimpleCatalog &refCat, geom::Angle matchCut, std::string const &fluxField, float refCoordinateErr, bool rejectBadFluxes=false)
Collect stars from an external reference catalog and associate them with fittedStars.
CcdImageList ccdImageList
FittedStarList fittedStarList
void prepareFittedStars(int minMeasurements)
Prepare the fittedStar list by making quality cuts and normalizing measurements.
void deprojectFittedStars()
Sends back the fitted stars coordinates on the sky FittedStarsList::inTangentPlaneCoordinates keeps t...
The base class for handling stars. Used by all matching routines.
Handler of an actual image from a single CCD.
MeasuredStarList const & getCatalogForFit() const
Gets the catalog to be used for fitting, which may have been cleaned-up.
FittedStars are objects whose position or flux is going to be fitted, and which come from the associa...
void setRefStar(const RefStar *_refStar)
Set the astrometric reference star associated with this star.
A list of FittedStar s. Such a list is typically constructed by Associations.
bool inTangentPlaneCoordinates
rectangle with sides parallel to axes.
bool inFrame(double x, double y) const
inside?
double xMin
coordinate of boundary.
Frame rescale(double factor) const
rescale it. The center does not move.
Sources measured on images.
std::shared_ptr< FittedStar > getFittedStar() const
double getMagWeight() const
the inverse of the mag variance
A list of MeasuredStar. They are usually filled in Associations::createCcdImage.
Objects used as position/flux anchors (e.g.
void applyTransform(const Operator &op)
enables to apply a geometrical transform if Star is Basestar or derives from it.
The transformation that handles pixels to sideral transformations (Gnomonic, possibly with polynomial...
virtual void apply(double xIn, double yIn, double &xOut, double &yOut) const=0
Transform pixels to ICRS RA, Dec in degrees.
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane)
virtual char const * what(void) const noexcept
static ConvexPolygon convexHull(std::vector< UnitVector3d > const &points)
Circle getBoundingCircle() const override
T emplace_back(T... args)
SpherePoint averageSpherePoint(std::vector< SpherePoint > const &coords)
AngleUnit constexpr degrees
constexpr double radToDeg(double x) noexcept
BaseStarList & Measured2Base(MeasuredStarList &This)
::std::list< StarMatch >::iterator StarMatchIterator
BaseStarList & Fitted2Base(FittedStarList &This)
std::unique_ptr< StarMatchList > listMatchCollect(const BaseStarList &list1, const BaseStarList &list2, const AstrometryTransform *guess, double maxDist)
assembles star matches.
BaseStarList & Ref2Base(RefStarList &This)
Class for a simple mapping implementing a generic AstrometryTransform.
std::string sourceFluxField
"name of flux field in source catalog" ;