48 auto workspace =
basis.makeWorkspace();
49 Eigen::MatrixXd matrix = Eigen::MatrixXd::Zero(input.
size(),
basis.size());
50 Eigen::VectorXd xRhs(input.
size());
51 Eigen::VectorXd yRhs(input.
size());
52 for (
int i = 0; i < matrix.rows(); ++i) {
53 basis.fill(input[i], matrix.row(i), workspace);
54 auto rhs = output[i] - input[i];
60 auto decomp = matrix.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV);
61 if (svdThreshold >= 0) {
62 decomp.setThreshold(svdThreshold);
74 if (shape.getX() <= 0 || shape.getY() <= 0) {
76 pex::exceptions::InvalidParameterError,
77 "Grid shape must be positive."
81 points.
reserve(shape.getX()*shape.getY());
82 double const dx =
bbox.getWidth()/shape.getX();
83 double const dy =
bbox.getHeight()/shape.getY();
84 for (
int iy = 0; iy < shape.getY(); ++iy) {
85 double const y =
bbox.getMinY() + iy*dy;
86 for (
int ix = 0; ix < shape.getX(); ++ix) {
95 LSST_THROW_IF_NE(coeffs.getSize<0>(), coeffs.getSize<1>(), pex::exceptions::InvalidParameterError,
96 "Coefficient matrix must be square (%d != %d).");
98 Eigen::VectorXd packed(
basis.size());
99 for (
auto const & i :
basis.getIndices()) {
100 packed[i.flat] = coeffs[i.nx][i.ny];
129 a(a_),
b(b_),
ap(ap_),
bp(bp_)
133 "A and B polynomials must have the same order (%d != %d).");
136 "A and AP polynomials must have the same order (%d != %d).");
139 "A and BP polynomials must have the same order (%d != %d).");
162 dpix1(makeGrid(parent._bbox, shape)),
163 siwc(parent._pixelToIwc->applyForward(dpix1))
168 if (parent._useInverse) {
171 dpix2 = parent._pixelToIwc->applyInverse(
siwc);
189 if (
basis.size() > parent._grid->dpix1.size()) {
192 (
boost::format(
"Number of parameters (%d) is larger than number of data points (%d)")
193 % (2*
basis.size()) % (2*parent._grid->dpix1.size())).str()
198 boxFwd.
shift(-parent._crpix);
199 auto fwd = fitSipOneDirection(order, boxFwd, svdThreshold, parent._grid->dpix1, parent._grid->siwc);
202 for (
auto const & point : parent._grid->siwc) {
205 auto inv = fitSipOneDirection(order, boxInv, svdThreshold, parent._grid->siwc, parent._grid->dpix2);
207 return std::make_unique<Solution>(fwd.first, fwd.second, inv.first, inv.second);
213 Eigen::Matrix2d
const &
cd,
220 _useInverse(useInverse),
221 _pixelToIwc(
std::move(pixelToIwc)),
224 _cdInv(
lsst::
geom::LinearTransform(
cd).inverted()),
225 _grid(new
Grid(gridShape, *this)),
226 _solution(
Solution::
fit(order, svdThreshold, *this))
232 Eigen::Matrix2d
const &
cd,
235 ndarray::Array<double const, 2>
const &
a,
236 ndarray::Array<double const, 2>
const &
b,
237 ndarray::Array<double const, 2>
const & ap,
238 ndarray::Array<double const, 2>
const & bp,
241 _useInverse(useInverse),
242 _pixelToIwc(
std::move(pixelToIwc)),
245 _cdInv(
lsst::
geom::LinearTransform(
cd).inverted()),
246 _grid(new
Grid(gridShape, *this)),
249 makePolynomialFromCoeffMatrix(
a),
250 makePolynomialFromCoeffMatrix(
b),
251 makePolynomialFromCoeffMatrix(ap),
252 makePolynomialFromCoeffMatrix(bp)
260 return _solution->a.getBasis().getOrder();
264 return _solution->a[_solution->a.getBasis().index(p, q)];
268 return _solution->b[_solution->b.getBasis().index(p, q)];
272 return _solution->ap[_solution->ap.getBasis().index(p, q)];
276 return _solution->bp[_solution->bp.getBasis().index(p, q)];
281 template <
typename F>
282 Eigen::MatrixXd makeCoefficientMatrix(
std::size_t order, F getter) {
283 Eigen::MatrixXd
result = Eigen::MatrixXd::Zero(order + 1, order + 1);
286 result(p, q) = getter(p, q);
295 return makeCoefficientMatrix(
297 [
this](
int p,
int q) {
return getA(p, q); }
302 return makeCoefficientMatrix(
304 [
this](
int p,
int q) {
return getB(p, q); }
309 return makeCoefficientMatrix(
311 [
this](
int p,
int q) {
return getAP(p, q); }
316 return makeCoefficientMatrix(
318 [
this](
int p,
int q) {
return getBP(p, q); }
324 auto ws = _solution->makeWorkspace();
325 return cd(_solution->applyForward(pix - _crpix, ws));
330 auto ws = _solution->makeWorkspace();
334 for (
auto const & point : pix) {
335 iwc.
push_back(
cd(_solution->applyForward(point - _crpix, ws)));
341 auto ws = _solution->makeWorkspace();
342 return _solution->applyInverse(_cdInv(iwc), ws) + _crpix;
347 auto ws = _solution->makeWorkspace();
350 for (
auto const & point : iwc) {
351 pix.
push_back(_solution->applyInverse(_cdInv(point), ws) + _crpix);
366 _grid = std::make_unique<Grid>(shape, *
this);
383 auto ws = _solution->makeWorkspace();
384 for (
std::size_t i = 0; i < _grid->dpix1.size(); ++i) {
385 auto siwc2 = _solution->applyForward(_grid->dpix1[i], ws);
386 auto dpix2 = _solution->applyInverse(_grid->siwc[i], ws);
387 maxDiff.first =
std::max(maxDiff.first, (_grid->siwc[i] - siwc2).computeNorm());
388 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.
typename Basis::Workspace Workspace
Type returned by makeWorkspace().
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++.
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.
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...
ScaledPolynomialBasis2d< PackingOrder::YX > ScaledPolynomialBasis2dYX
A Basis2d for scaled standard polynomials, ordered via PackingOrder::YX.
Extent< double, 2 > Extent2D
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
A base class for image defects.
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