58 int const SERIALIZATION_VERSION = 1;
66 double const TIGHT_FITS_TOL = 0.0001;
68 class SkyWcsPersistenceHelper {
71 table::Key<table::Array<std::uint8_t>>
wcs;
73 static SkyWcsPersistenceHelper
const& get() {
74 static SkyWcsPersistenceHelper instance;
79 SkyWcsPersistenceHelper(
const SkyWcsPersistenceHelper&) =
delete;
80 SkyWcsPersistenceHelper&
operator=(
const SkyWcsPersistenceHelper&) =
delete;
83 SkyWcsPersistenceHelper(SkyWcsPersistenceHelper&&) =
delete;
84 SkyWcsPersistenceHelper&
operator=(SkyWcsPersistenceHelper&&) =
delete;
87 SkyWcsPersistenceHelper()
89 wcs(
schema.addField<table::Array<
std::uint8_t>>(
"wcs",
"wcs string representation",
"")) {}
92 class SkyWcsFactory :
public table::io::PersistableFactory {
97 CatalogVector
const& catalogs)
const override {
98 SkyWcsPersistenceHelper
const&
keys = SkyWcsPersistenceHelper::get();
102 table::BaseRecord
const& record = catalogs.front().front();
104 return SkyWcs::readString(stringRep);
108 std::string getSkyWcsPersistenceName() {
return "SkyWcs"; }
110 SkyWcsFactory registration(getSkyWcsPersistenceName());
117 auto const initialWcs =
119 auto const initialFrameDict = initialWcs->getFrameDict();
120 auto const iwcToSkyMap = initialFrameDict->getMapping(
"IWC",
"SKY");
121 auto const pixelFrame = initialFrameDict->getFrame(
"PIXELS");
122 auto const iwcFrame = initialFrameDict->getFrame(
"IWC");
123 auto const skyFrame = initialFrameDict->getFrame(
"SKY");
126 ndarray::Array<double, 2, 2> fieldAngleToIwcNdArray = ndarray::allocate(2, 2);
127 asEigenMatrix(fieldAngleToIwcNdArray) = orientationAndFlipXMatrix * 180.0 /
lsst::geom::PI;
128 auto const pixelsToFieldAngleMap = pixelsToFieldAngle.getMapping();
129 auto const fieldAngleToIwcMap =
ast::MatrixMap(fieldAngleToIwcNdArray);
130 auto const pixelsToIwcMap = pixelsToFieldAngleMap->then(fieldAngleToIwcMap);
131 auto finalFrameDict =
ast::FrameDict(*pixelFrame, pixelsToIwcMap, *iwcFrame);
132 finalFrameDict.addFrame(
"IWC", *iwcToSkyMap, *skyFrame);
133 return finalFrameDict;
140 Eigen::Matrix2d cdMatrix;
142 double scaleDeg =
scale.asDegrees();
143 double xmult = flipX ? 1.0 : -1.0;
144 cdMatrix(0, 0) =
std::cos(orientRad) * scaleDeg * xmult;
145 cdMatrix(0, 1) =
std::sin(orientRad) * scaleDeg;
146 cdMatrix(1, 0) = -
std::sin(orientRad) * scaleDeg * xmult;
147 cdMatrix(1, 1) =
std::cos(orientRad) * scaleDeg;
153 return src.getTransform()->then(*dstInverse);
166 double const side = 1.0;
176 auto skyLL = skyVec[0].getVector();
177 auto skyDx = skyVec[1].getVector() - skyLL;
178 auto skyDy = skyVec[2].getVector() - skyLL;
183 double skyAreaSq = skyDx.cross(skyDy).getSquaredNorm();
189 auto skyFrame = std::dynamic_pointer_cast<ast::SkyFrame>(
194 auto const crvalRad = skyFrame->getSkyRef();
201 return pixelToIwcTransform.getJacobian(
pixel);
210 return std::make_shared<SkyWcs>(*metadata);
223 auto const iwcToSky = thisDict->getMapping(
"IWC",
"SKY");
224 auto const gridToSky = gridToPixel.
then(*pixelToIwc).
then(*iwcToSky);
229 os <<
"Encoding=FITS-WCS, CDMatrix=1, FitsAxisOrder=<copy>, FitsTol=" << TIGHT_FITS_TOL;
234 if (nObjectsWritten == 0) {
237 "Could not represent this SkyWcs using FITS-WCS metadata");
242 header = tanWcs->getFitsMetadata(
true);
249 header->remove(
"DATE-OBS");
250 header->remove(
"MJD-OBS");
253 bool const hasCd11 = header->exists(
"CD1_1");
254 bool const hasCd12 = header->exists(
"CD1_2");
255 bool const hasCd21 = header->exists(
"CD2_1");
256 bool const hasCd22 = header->exists(
"CD2_2");
257 if (hasCd11 || hasCd12 || hasCd21 || hasCd22) {
258 if (!hasCd11) header->set(
"CD1_1", 0.0,
"Transformation matrix element");
259 if (!hasCd12) header->set(
"CD1_2", 0.0,
"Transformation matrix element");
260 if (!hasCd21) header->set(
"CD2_1", 0.0,
"Transformation matrix element");
261 if (!hasCd22) header->set(
"CD2_2", 0.0,
"Transformation matrix element");
282 return _linearizePixelToSky(
skyToPixel(coord), coord, skyUnit);
286 return _linearizePixelToSky(pix,
pixelToSky(pix), skyUnit);
291 return _linearizeSkyToPixel(
skyToPixel(coord), coord, skyUnit);
296 return _linearizeSkyToPixel(pix,
pixelToSky(pix), skyUnit);
316 is >> shortClassName;
326 auto frameSet = std::dynamic_pointer_cast<ast::FrameSet>(astObjectPtr);
329 os <<
"The AST serialization was read as a " << astObjectPtr->getClassName()
330 <<
" instead of a FrameSet";
334 return std::make_shared<SkyWcs>(frameDict);
354 return std::make_unique<SkyWcs>(*
this);
360 os <<
"FITS standard SkyWcs:";
362 os <<
"Non-standard SkyWcs (Frames: ";
379 return singleClassEquals(*
this,
other);
387 SkyWcsPersistenceHelper
const&
keys = SkyWcsPersistenceHelper::get();
395 : _frameDict(frameDict), _transform(), _pixelOrigin(), _pixelScaleAtOrigin(0 *
lsst::
geom::
radians) {
402 for (
auto const& domainName : domainNames) {
404 auto const frame = frameDict.
getFrame(domainName,
false);
405 if (frame->getNAxes() != 2) {
407 "Frame " + domainName +
" has " +
std::to_string(frame->getNAxes()) +
408 " axes instead of 2");
410 auto desiredClassName = domainName ==
"SKY" ?
"SkyFrame" :
"Frame";
411 if (frame->getClassName() != desiredClassName) {
413 "Frame " + domainName +
" is of type " + frame->getClassName() +
414 " instead of " + desiredClassName);
416 }
else if (domainName !=
"ACTUAL_PIXELS") {
419 "No frame with domain " + domainName +
" found");
425 if (baseDomain !=
"ACTUAL_PIXELS" && baseDomain !=
"PIXELS") {
427 "Base frame has domain " + baseDomain +
" instead of PIXELS or ACTUAL_PIXELS");
432 if (currentDomain !=
"SKY") {
434 "Current frame has domain " + currentDomain +
" instead of SKY");
437 return frameDict.
copy();
446 const double side = 1.0;
452 m(0, 0) = dsky10.first.asAngularUnits(skyUnit) / side;
453 m(0, 1) = dsky01.first.asAngularUnits(skyUnit) / side;
454 m(1, 0) = dsky10.second.asAngularUnits(skyUnit) / side;
455 m(1, 1) = dsky01.second.asAngularUnits(skyUnit) / side;
457 Eigen::Vector2d sky00v;
458 sky00v << sky00.getX(), sky00.getY();
459 Eigen::Vector2d pix00v;
460 pix00v << pix00.getX(), pix00.getY();
474 double const dx = 1000;
492 bool modifyActualPixels) {
493 auto const pixelMapping = pixelTransform.
getMapping();
494 auto oldFrameDict =
wcs.getFrameDict();
495 bool const hasActualPixels = oldFrameDict->hasDomain(
"ACTUAL_PIXELS");
496 auto const pixelFrame = oldFrameDict->getFrame(
"PIXELS",
false);
497 auto const iwcFrame = oldFrameDict->getFrame(
"IWC",
false);
498 auto const skyFrame = oldFrameDict->getFrame(
"SKY",
false);
499 auto const oldPixelToIwc = oldFrameDict->getMapping(
"PIXELS",
"IWC");
500 auto const iwcToSky = oldFrameDict->getMapping(
"IWC",
"SKY");
504 if (hasActualPixels) {
505 auto const actualPixelFrame = oldFrameDict->getFrame(
"ACTUAL_PIXELS",
false);
506 auto const oldActualPixelToPixels = oldFrameDict->getMapping(
"ACTUAL_PIXELS",
"PIXELS");
508 if (modifyActualPixels) {
509 newActualPixelsToPixels = pixelMapping->
then(*oldActualPixelToPixels).
simplified();
510 newPixelToIwc = oldPixelToIwc;
512 newActualPixelsToPixels = oldActualPixelToPixels;
516 std::make_shared<ast::FrameDict>(*actualPixelFrame, *newActualPixelsToPixels, *pixelFrame);
517 newFrameDict->addFrame(
"PIXELS", *newPixelToIwc, *iwcFrame);
520 newFrameDict = std::make_shared<ast::FrameDict>(*pixelFrame, *newPixelToIwc, *iwcFrame);
522 newFrameDict->addFrame(
"IWC", *iwcToSky, *skyFrame);
523 return std::make_shared<SkyWcs>(*newFrameDict);
527 return std::make_shared<SkyWcs>(metadata,
strip);
531 Eigen::Matrix2d
const& cdMatrix,
std::string const& projection) {
533 return std::make_shared<SkyWcs>(*metadata);
539 auto frameDict = makeSkyWcsFrameDict(pixelsToFieldAngle,
orientation, flipX, boresight, projection);
540 return std::make_shared<SkyWcs>(frameDict);
544 Eigen::Matrix2d
const& cdMatrix, Eigen::MatrixXd
const& sipA,
545 Eigen::MatrixXd
const& sipB) {
547 return std::make_shared<SkyWcs>(*metadata);
551 Eigen::Matrix2d
const& cdMatrix, Eigen::MatrixXd
const& sipA,
552 Eigen::MatrixXd
const& sipB, Eigen::MatrixXd
const& sipAp,
553 Eigen::MatrixXd
const& sipBp) {
555 return std::make_shared<SkyWcs>(*metadata);
560 auto iwcToSky =
wcs.getFrameDict()->getMapping(
"IWC",
"SKY");
561 return std::make_shared<TransformPoint2ToSpherePoint>(*iwcToSky, simplify);
566 return std::make_shared<TransformPoint2ToPoint2>(*pixelToIwc, simplify);
570 os <<
wcs.toString();
table::PointKey< int > pixel
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
std::shared_ptr< RecordT > src
table::PointKey< double > crpix
table::PointKey< double > crval
ItemVariant const * other
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Channel provides input/output of AST objects.
std::shared_ptr< Object > read()
Read an object from a channel.
int write(Object const &object)
Write an object to a channel.
A specialized form of Channel which reads and writes FITS header cards.
A FrameSet whose frames can be referenced by domain name.
bool hasDomain(std::string const &domain) const
Return True if a frame in this FrameDict has the specified domain.
std::shared_ptr< FrameDict > copy() const
Return a deep copy of this object.
std::set< std::string > getAllDomains() const
Get the domain names for all contained Frames (excluding frames with empty or defaulted domain names)...
std::shared_ptr< Mapping > getMapping(int from, std::string const &to) const
Variant of FrameSet::getMapping with the second frame specified by domain.
std::shared_ptr< Frame > getFrame(std::string const &domain, bool copy=true) const
Variant of getFrame(int, bool) where the frame is specified by domain name.
Frame is used to represent a coordinate system.
A FrameSet consists of a set of one or more Frames (which describe coordinate systems),...
static constexpr int CURRENT
index of current frame
static constexpr int BASE
index of base frame
SeriesMap then(Mapping const &next) const
Return a series compound mapping this(first(input)) containing shallow copies of the original.
std::shared_ptr< Mapping > simplified() const
Return a simplied version of the mapping (which may be a compound Mapping such as a CmpMap).
MatrixMap is a form of Mapping which performs a general linear transformation.
void show(std::ostream &os, bool showComments=true) const
Print a textual description the object to an ostream.
ShiftMap is a linear Mapping which shifts each axis by a specified constant value.
A stream for ast::Channel.
String-based source and sink for channels.
A WinMap is a linear Mapping which transforms a rectangular window in one coordinate system into a si...
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
Eigen::Matrix2d getCdMatrix() const
Get the 2x2 CD matrix at the pixel origin.
std::string writeString() const
Serialize this SkyWcs to a string, using the same format as writeStream.
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
std::shared_ptr< SkyWcs > copyAtShiftedPixelOrigin(lsst::geom::Extent2D const &shift) const
Return a copy of this SkyWcs with the pixel origin shifted by the specified amount.
static std::shared_ptr< SkyWcs > readStream(std::istream &is)
Deserialize a SkyWcs from an input stream.
std::shared_ptr< SkyWcs > getTanWcs(lsst::geom::Point2D const &pixel) const
Get a local TAN WCS approximation to this WCS at the specified pixel position.
lsst::geom::Angle getPixelScale() const
Get the pixel scale at the pixel origin.
static std::shared_ptr< SkyWcs > readString(std::string &str)
Deserialize a SkyWcs from a string, using the same format as readStream.
lsst::geom::SpherePoint getSkyOrigin() const
Get the sky origin, the celestial fiducial point.
std::string toString() const override
Create a string representation of this object.
lsst::geom::Point2D getPixelOrigin() const
Get the pixel origin, in pixels, using the LSST convention.
lsst::geom::AffineTransform linearizePixelToSky(lsst::geom::SpherePoint const &coord, lsst::geom::AngleUnit const &skyUnit) const
Return the local linear approximation to pixelToSky at a point given in sky coordinates.
bool operator==(SkyWcs const &other) const
Equality is based on the string representations being equal.
lsst::geom::AffineTransform linearizeSkyToPixel(lsst::geom::SpherePoint const &coord, lsst::geom::AngleUnit const &skyUnit) const
Return the local linear approximation to skyToPixel at a point given in sky coordinates.
SkyWcs(SkyWcs const &)=default
lsst::geom::Point2D skyToPixel(lsst::geom::SpherePoint const &sky) const
Compute pixel position(s) from sky position(s)
std::string getPythonModule() const override
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
bool isFlipped() const
Does the WCS follow the convention of North=Up, East=Left?
std::shared_ptr< daf::base::PropertyList > getFitsMetadata(bool precise=false) const
Return the WCS as FITS WCS metadata.
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
bool hasFitsApproximation() const
Does this SkyWcs have an approximate SkyWcs that can be represented as standard FITS WCS?
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
bool equals(typehandling::Storable const &other) const noexcept override
Compare this object to another Storable.
std::shared_ptr< const TransformPoint2ToSpherePoint > getTransform() const
Get a TransformPoint2ToSpherePoint that transforms pixels to sky in the forward direction and sky to ...
void writeStream(std::ostream &os) const
Serialize this SkyWcs to an output stream.
std::shared_ptr< typehandling::Storable > cloneStorable() const override
Create a new SkyWcs that is a copy of this one.
static std::string getShortClassName()
std::shared_ptr< const ast::FrameDict > getFrameDict() const
Get the contained FrameDict.
bool isFits() const
Return true getFitsMetadata(true) will succeed, false if not.
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
Interface supporting iteration over heterogenous containers.
Class for storing generic metadata.
A class representing an angle.
constexpr double asArcseconds() const noexcept
Return an Angle's value in arcseconds.
A class used to convert scalar POD types such as double to Angle.
Point in an unspecified spherical coordinate system.
std::pair< Angle, Angle > getTangentPlaneOffset(SpherePoint const &other) const
Get the offset from a tangent plane centered at this point to another point.
Point2D getPosition(AngleUnit unit) const noexcept
Return longitude, latitude as a Point2D object.
Reports errors in the logical structure of the program.
Reports errors that are due to events beyond the control of the program.
Reports errors from accepting an object of an unexpected or inappropriate type.
def scale(algorithm, min, max=None, frame=None)
std::shared_ptr< ast::FrameDict > readLsstSkyWcs(daf::base::PropertySet &metadata, bool strip=true)
Read an LSST celestial WCS FrameDict from a FITS header.
std::shared_ptr< daf::base::PropertyList > getPropertyListFromFitsChan(ast::FitsChan &fitsChan)
Copy values from an AST FitsChan into a PropertyList.
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
std::shared_ptr< daf::base::PropertyList > makeSimpleWcsMetadata(lsst::geom::Point2D const &crpix, lsst::geom::SpherePoint const &crval, Eigen::Matrix2d const &cdMatrix, std::string const &projection="TAN")
Make FITS metadata for a simple FITS WCS (one with no distortion).
std::shared_ptr< TransformPoint2ToPoint2 > getPixelToIntermediateWorldCoords(SkyWcs const &wcs, bool simplify=true)
Return a transform from pixel coordinates to intermediate world coordinates.
std::shared_ptr< SkyWcs > makeTanSipWcs(lsst::geom::Point2D const &crpix, lsst::geom::SpherePoint const &crval, Eigen::Matrix2d const &cdMatrix, Eigen::MatrixXd const &sipA, Eigen::MatrixXd const &sipB)
Construct a TAN-SIP SkyWcs with forward SIP distortion terms and an iterative inverse.
std::ostream & operator<<(std::ostream &os, GenericEndpoint const &endpoint)
Print "GenericEndpoint(_n_)" to the ostream where _n_ is the number of axes, e.g. "GenericAxes(4)".
Eigen::Matrix2d makeCdMatrix(lsst::geom::Angle const &scale, lsst::geom::Angle const &orientation=0 *lsst::geom::degrees, bool flipX=false)
Make a WCS CD matrix.
std::shared_ptr< TransformPoint2ToSpherePoint > getIntermediateWorldCoordsToSky(SkyWcs const &wcs, bool simplify=true)
Return a transform from intermediate world coordinates to sky.
std::shared_ptr< daf::base::PropertyList > makeTanSipMetadata(lsst::geom::Point2D const &crpix, lsst::geom::SpherePoint const &crval, Eigen::Matrix2d const &cdMatrix, Eigen::MatrixXd const &sipA, Eigen::MatrixXd const &sipB)
Make metadata for a TAN-SIP WCS without inverse matrices.
std::shared_ptr< SkyWcs > makeModifiedWcs(TransformPoint2ToPoint2 const &pixelTransform, SkyWcs const &wcs, bool modifyActualPixels)
Create a new SkyWcs whose pixels are transformed by pixelTransform, as described below.
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
std::shared_ptr< SkyWcs > makeFlippedWcs(SkyWcs const &wcs, bool flipLR, bool flipTB, lsst::geom::Point2D const ¢er)
Return a copy of a FITS-WCS with pixel positions flipped around a specified center.
FilterProperty & operator=(FilterProperty const &)=default
lsst::geom::SpherePoint SpherePoint
constexpr double PI
The ratio of a circle's circumference to diameter.
Extent< double, 2 > Extent2D
constexpr AngleUnit degrees
constant with units of degrees
constexpr AngleUnit radians
constant with units of radians
int orientation(UnitVector3d const &a, UnitVector3d const &b, UnitVector3d const &c)
orientation computes and returns the orientations of 3 unit vectors a, b and c.
A base class for image defects.
table::Key< table::Array< std::uint8_t > > wcs