31 namespace lsst {
namespace afw {
namespace geom {
33 namespace poly = lsst::geom::polynomials;
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);
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).");
146 return dpix +
Extent2D(
a(dpix, ws),
b(dpix, ws));
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()
196 Box2D boxFwd(parent._bbox);
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)),
224 _grid(new
Grid(gridShape, *this)),
225 _solution(
Solution::
fit(order, svdThreshold, *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)),
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)];
280 template <
typename F>
281 Eigen::MatrixXd makeCoefficientMatrix(
std::size_t order, F getter) {
282 Eigen::MatrixXd
result = Eigen::MatrixXd::Zero(order + 1, order + 1);
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));
328 auto ws = _solution->makeWorkspace();
332 for (
auto const & point : pix) {
333 iwc.
push_back(
cd(_solution->applyForward(point - _crpix, ws)));
339 auto ws = _solution->makeWorkspace();
340 return _solution->applyInverse(_cdInv(iwc), ws) + _crpix;
344 auto ws = _solution->makeWorkspace();
347 for (
auto const & point : iwc) {
348 pix.
push_back(_solution->applyInverse(_cdInv(point), ws) + _crpix);
363 _grid = std::make_unique<Grid>(shape, *
this);
380 auto ws = _solution->makeWorkspace();
381 for (
std::size_t i = 0; i < _grid->dpix1.size(); ++i) {
382 auto siwc2 = _solution->applyForward(_grid->dpix1[i], ws);
383 auto dpix2 = _solution->applyInverse(_grid->siwc[i], ws);
384 maxDiff.first =
std::max(maxDiff.first, (_grid->siwc[i] - siwc2).computeNorm());
385 maxDiff.second =
std::max(maxDiff.second, (_grid->dpix2[i] - dpix2).computeNorm());