47 auto workspace =
basis.makeWorkspace();
48 Eigen::MatrixXd matrix = Eigen::MatrixXd::Zero(input.
size(),
basis.size());
49 Eigen::VectorXd xRhs(input.
size());
50 Eigen::VectorXd yRhs(input.
size());
51 for (
int i = 0; i < matrix.rows(); ++i) {
52 basis.fill(input[i], matrix.row(i), workspace);
53 auto rhs = output[i] - input[i];
59 auto decomp = matrix.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV);
60 if (svdThreshold >= 0) {
61 decomp.setThreshold(svdThreshold);
73 if (shape.getX() <= 0 || shape.getY() <= 0) {
75 pex::exceptions::InvalidParameterError,
76 "Grid shape must be positive."
80 points.
reserve(shape.getX()*shape.getY());
81 double const dx =
bbox.getWidth()/shape.getX();
82 double const dy =
bbox.getHeight()/shape.getY();
83 for (
int iy = 0; iy < shape.getY(); ++iy) {
84 double const y =
bbox.getMinY() + iy*dy;
85 for (
int ix = 0; ix < shape.getX(); ++ix) {
94 LSST_THROW_IF_NE(coeffs.getSize<0>(), coeffs.getSize<1>(), pex::exceptions::InvalidParameterError,
95 "Coefficient matrix must be square (%d != %d).");
97 Eigen::VectorXd packed(
basis.size());
98 for (
auto const & i :
basis.getIndices()) {
99 packed[i.flat] = coeffs[i.nx][i.ny];
128 a(a_),
b(b_),
ap(ap_),
bp(bp_)
132 "A and B polynomials must have the same order (%d != %d).");
135 "A and AP polynomials must have the same order (%d != %d).");
138 "A and BP polynomials must have the same order (%d != %d).");
141 using Workspace = poly::PolynomialFunction2dYX::Workspace;
161 dpix1(makeGrid(parent._bbox, shape)),
162 siwc(parent._pixelToIwc->applyForward(dpix1))
167 if (parent._useInverse) {
170 dpix2 = parent._pixelToIwc->applyInverse(
siwc);
188 if (
basis.size() > parent._grid->dpix1.size()) {
191 (boost::format(
"Number of parameters (%d) is larger than number of data points (%d)")
192 % (2*
basis.size()) % (2*parent._grid->dpix1.size())).str()
197 boxFwd.
shift(-parent._crpix);
198 auto fwd = fitSipOneDirection(
order, boxFwd, svdThreshold, parent._grid->dpix1, parent._grid->siwc);
201 for (
auto const & point : parent._grid->siwc) {
204 auto inv = fitSipOneDirection(
order, boxInv, svdThreshold, parent._grid->siwc, parent._grid->dpix2);
206 return std::make_unique<Solution>(fwd.first, fwd.second, inv.first, inv.second);
212 Eigen::Matrix2d
const &
cd,
219 _useInverse(useInverse),
220 _pixelToIwc(
std::move(pixelToIwc)),
223 _cdInv(
lsst::
geom::LinearTransform(
cd).inverted()),
224 _grid(new
Grid(gridShape, *this)),
231 Eigen::Matrix2d
const &
cd,
234 ndarray::Array<double const, 2>
const &
a,
235 ndarray::Array<double const, 2>
const &
b,
236 ndarray::Array<double const, 2>
const & ap,
237 ndarray::Array<double const, 2>
const & bp,
240 _useInverse(useInverse),
241 _pixelToIwc(
std::move(pixelToIwc)),
244 _cdInv(
lsst::
geom::LinearTransform(
cd).inverted()),
245 _grid(new
Grid(gridShape, *this)),
248 makePolynomialFromCoeffMatrix(
a),
249 makePolynomialFromCoeffMatrix(
b),
250 makePolynomialFromCoeffMatrix(ap),
251 makePolynomialFromCoeffMatrix(bp)
259 return _solution->a.getBasis().
getOrder();
263 return _solution->a[_solution->a.getBasis().index(p, q)];
267 return _solution->b[_solution->b.getBasis().index(p, q)];
271 return _solution->ap[_solution->ap.getBasis().index(p, q)];
275 return _solution->bp[_solution->bp.getBasis().index(p, q)];
285 result(p, q) = getter(p, q);
294 return makeCoefficientMatrix(
296 [
this](
int p,
int q) {
return getA(p, q); }
301 return makeCoefficientMatrix(
303 [
this](
int p,
int q) {
return getB(p, q); }
308 return makeCoefficientMatrix(
310 [
this](
int p,
int q) {
return getAP(p, q); }
315 return makeCoefficientMatrix(
317 [
this](
int p,
int q) {
return getBP(p, q); }
323 auto ws = _solution->makeWorkspace();
324 return cd(_solution->applyForward(pix - _crpix, ws));
329 auto ws = _solution->makeWorkspace();
333 for (
auto const & point : pix) {
334 iwc.
push_back(
cd(_solution->applyForward(point - _crpix, ws)));
340 auto ws = _solution->makeWorkspace();
341 return _solution->applyInverse(_cdInv(iwc), ws) + _crpix;
346 auto ws = _solution->makeWorkspace();
349 for (
auto const & point : iwc) {
350 pix.
push_back(_solution->applyInverse(_cdInv(point), ws) + _crpix);
365 _grid = std::make_unique<Grid>(shape, *
this);
382 auto ws = _solution->makeWorkspace();
383 for (
std::size_t i = 0; i < _grid->dpix1.size(); ++i) {
384 auto siwc2 = _solution->applyForward(_grid->dpix1[i], ws);
385 auto dpix2 = _solution->applyInverse(_grid->siwc[i], ws);
386 maxDiff.first =
std::max(maxDiff.first, (_grid->siwc[i] - siwc2).computeNorm());
387 maxDiff.second =
std::max(maxDiff.second, (_grid->dpix2[i] - dpix2).computeNorm());
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
table::PointKey< double > crpix
table::Key< table::Array< double > > cd
#define LSST_THROW_IF_NE(N1, N2, EXC_CLASS, MSG)
Check whether the given values are equal, and throw an LSST Exception if they are not.
A fitter and results class for approximating a general Transform in a form compatible with FITS WCS p...
void fit(int order, double svdThreshold=-1)
Obtain a new solution at the given order with the current grid.
lsst::geom::Extent2I getGridShape() const noexcept
Return the number of grid points in x and y.
Eigen::MatrixXd getBP() const noexcept
Return the coefficients of the reverse transform polynomial.
Eigen::MatrixXd getAP() const noexcept
Return the coefficients of the reverse transform polynomial.
Eigen::MatrixXd getA() const noexcept
Return the coefficients of the forward transform polynomial.
int getOrder() const noexcept
Return the polynomial order of the current solution (same for forward and reverse).
lsst::geom::Extent2D getGridStep() const noexcept
Return the distance between grid points in pixels.
void updateGrid(lsst::geom::Extent2I const &shape)
Update the grid to the given number of points in x and y.
void refineGrid(int factor=2)
Update the grid by making it finer by a given integer factor.
~SipApproximation() noexcept
lsst::geom::Point2D applyInverse(lsst::geom::Point2D const &iwcs) const
Convert a point from intermediate world coordinates to pixels.
Eigen::MatrixXd getB() const noexcept
Return the coefficients of the forward transform polynomial.
std::pair< double, double > computeMaxDeviation() const noexcept
Return the maximum deviation of the solution from the exact transform on the current grid.
lsst::geom::Point2D applyForward(lsst::geom::Point2D const &pix) const
Convert a point from pixels to intermediate world coordinates.
SipApproximation(std::shared_ptr< TransformPoint2ToPoint2 > pixelToIwc, lsst::geom::Point2D const &crpix, Eigen::Matrix2d const &cd, lsst::geom::Box2D const &bbox, lsst::geom::Extent2I const &gridShape, int order, bool useInverse=true, double svdThreshold=-1)
Construct a new approximation by fitting on a grid of points.
A floating-point coordinate rectangle geometry.
void shift(Extent2D const &offset)
Shift the position of the box by the given offset.
double getWidth() const noexcept
1-d interval accessors
void include(Point2D const &point) noexcept
Expand this to ensure that this->contains(point).
double getHeight() const noexcept
1-d interval accessors
A 2-d function defined by a series expansion and its coefficients.
Workspace makeWorkspace() const
Allocate workspace that can be passed to operator() to avoid repeated memory allocations.
Basis const & getBasis() const
Return the associated Basis2d object.
A Basis2d formed from the product of a Basis1d for each of x and y, truncated at the sum of their ord...
Reports invalid arguments.
Reports errors in the logical structure of the program.
T emplace_back(T... args)
Low-level polynomials (including special polynomials) in C++.
Function2d< Basis > makeFunction2d(Basis const &basis, Eigen::VectorXd const &coefficients)
Create a Function2d of the appropriate type from a Basis2d and an Eigen object containing coefficient...
PolynomialFunction1d simplified(ScaledPolynomialFunction1d const &f)
Calculate the standard polynomial function that is equivalent to a scaled standard polynomial functio...
PolynomialFunction2d< PackingOrder::YX > PolynomialFunction2dYX
A Function2d for standard polynomials, ordered via PackingOrder::YX.
ScaledPolynomialBasis2d< PackingOrder::YX > ScaledPolynomialBasis2dYX
A Basis2d for scaled standard polynomials, ordered via PackingOrder::YX.
Extent< double, 2 > Extent2D
table::Key< table::Array< double > > basis
Grid(lsst::geom::Extent2I const &shape_, SipApproximation const &parent)
std::vector< lsst::geom::Point2D > dpix1
std::vector< lsst::geom::Point2D > dpix2
std::vector< lsst::geom::Point2D > siwc
lsst::geom::Extent2I const shape
poly::PolynomialFunction2dYX bp
poly::PolynomialFunction2dYX a
static std::unique_ptr< Solution > fit(int order_, double svdThreshold, SipApproximation const &parent)
Workspace makeWorkspace() const
lsst::geom::Point2D applyInverse(lsst::geom::Point2D const &siwc, Workspace &ws) const
Solution(poly::PolynomialFunction2dYX const &a_, poly::PolynomialFunction2dYX const &b_, poly::PolynomialFunction2dYX const &ap_, poly::PolynomialFunction2dYX const &bp_)
poly::PolynomialFunction2dYX b
lsst::geom::Point2D applyForward(lsst::geom::Point2D const &dpix, Workspace &ws) const
poly::PolynomialFunction2dYX::Workspace Workspace
poly::PolynomialFunction2dYX ap