LSSTApplications  21.0.0+75b29a8a7f,21.0.0+e70536a077,21.0.0-1-ga51b5d4+62c747d40b,21.0.0-11-ga6ea59e8e+47cba9fc36,21.0.0-2-g103fe59+914993bf7c,21.0.0-2-g1367e85+e2614ded12,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g4bc9b9f+7b2b5f8678,21.0.0-2-g5242d73+e2614ded12,21.0.0-2-g54e2caa+6403186824,21.0.0-2-g7f82c8f+3ac4acbffc,21.0.0-2-g8dde007+04a6aea1af,21.0.0-2-g8f08a60+9402881886,21.0.0-2-ga326454+3ac4acbffc,21.0.0-2-ga63a54e+81dd751046,21.0.0-2-gc738bc1+5f65c6e7a9,21.0.0-2-gde069b7+26c92b3210,21.0.0-2-gecfae73+0993ddc9bd,21.0.0-2-gfc62afb+e2614ded12,21.0.0-21-gba890a8+5a4f502a26,21.0.0-23-g9966ff26+03098d1af8,21.0.0-3-g357aad2+8ad216c477,21.0.0-3-g4be5c26+e2614ded12,21.0.0-3-g6d51c4a+4d2fe0280d,21.0.0-3-g7d9da8d+75b29a8a7f,21.0.0-3-gaa929c8+522e0f12c2,21.0.0-3-ge02ed75+4d2fe0280d,21.0.0-4-g3300ddd+e70536a077,21.0.0-4-gc004bbf+eac6615e82,21.0.0-4-gccdca77+f94adcd104,21.0.0-4-gd1c1571+18b81799f9,21.0.0-5-g7b47fff+4d2fe0280d,21.0.0-5-gb155db7+d2632f662b,21.0.0-5-gdf36809+637e4641ee,21.0.0-6-g722ad07+28c848f42a,21.0.0-7-g959bb79+522e0f12c2,21.0.0-7-gfd72ab2+cf01990774,21.0.0-9-g87fb7b8d+e2ab11cdd6,w.2021.04
LSSTDataManagementBasePackage
BasisLists.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
11 #include <cmath>
12 #include <limits>
13 
14 #include "boost/timer.hpp"
15 
18 #include "lsst/afw/image.h"
19 #include "lsst/afw/math.h"
20 #include "lsst/geom.h"
21 #include "lsst/log/Log.h"
23 
25 namespace geom = lsst::geom;
26 namespace afwImage = lsst::afw::image;
27 namespace afwMath = lsst::afw::math;
28 
29 namespace lsst {
30 namespace ip {
31 namespace diffim {
32 
48  int width,
49  int height
50  ) {
51  if ((width < 1) || (height < 1)) {
52  throw LSST_EXCEPT(pexExcept::Exception, "nRows and nCols must be positive");
53  }
54  const int signedWidth = static_cast<int>(width);
55  const int signedHeight = static_cast<int>(height);
56  afwMath::KernelList kernelBasisList;
57  for (int row = 0; row < signedHeight; ++row) {
58  for (int col = 0; col < signedWidth; ++col) {
60  kernelPtr(new afwMath::DeltaFunctionKernel(width, height, geom::Point2I(col,row)));
61  kernelBasisList.push_back(kernelPtr);
62  }
63  }
64  return kernelBasisList;
65  }
66 
79  int halfWidth,
80  int nGauss,
81  std::vector<double> const &sigGauss,
82  std::vector<int> const &degGauss
83  ) {
85  typedef afwImage::Image<Pixel> Image;
86 
87  if (halfWidth < 1) {
88  throw LSST_EXCEPT(pexExcept::Exception, "halfWidth must be positive");
89  }
90  if (nGauss != static_cast<int>(sigGauss.size())) {
91  throw LSST_EXCEPT(pexExcept::Exception, "sigGauss does not have enough entries");
92  }
93  if (nGauss != static_cast<int>(degGauss.size())) {
94  throw LSST_EXCEPT(pexExcept::Exception, "degGauss does not have enough entries");
95  }
96  int fullWidth = 2 * halfWidth + 1;
97  Image image(geom::Extent2I(fullWidth, fullWidth));
98 
99  afwMath::KernelList kernelBasisList;
100  for (int i = 0; i < nGauss; i++) {
101  /*
102  sigma = FWHM / ( 2 * sqrt(2 * ln(2)) )
103  */
104  double sig = sigGauss[i];
105  int deg = degGauss[i];
106 
107  LOGL_DEBUG("TRACE1.ip.diffim.BasisLists.makeAlardLuptonBasisList",
108  "Gaussian %d : sigma %.2f degree %d", i, sig, deg);
109 
110  afwMath::GaussianFunction2<Pixel> gaussian(sig, sig);
111  afwMath::AnalyticKernel kernel(fullWidth, fullWidth, gaussian);
112  afwMath::PolynomialFunction2<Pixel> polynomial(deg);
113 
114  for (int j = 0, n = 0; j <= deg; j++) {
115  for (int k = 0; k <= (deg - j); k++, n++) {
116  /* for 0th order term, skip polynomial */
117  (void)kernel.computeImage(image, true);
118  if (n == 0) {
120  kernelPtr(new afwMath::FixedKernel(image));
121  kernelBasisList.push_back(kernelPtr);
122  continue;
123  }
124 
125  /* gaussian to be modified by this term in the polynomial */
126  polynomial.setParameter(n, 1.);
127  (void)kernel.computeImage(image, true);
128  for (int y = 0, v = -halfWidth; y < image.getHeight(); y++, v++) {
129  int u = -halfWidth;
130  for (Image::xy_locator ptr = image.xy_at(0, y),
131  end = image.xy_at(image.getWidth(), y);
132  ptr != end; ++ptr.x(), u++) {
133  /* Evaluate from -1 to 1 */
134  *ptr = *ptr * polynomial(u/static_cast<double>(halfWidth),
135  v/static_cast<double>(halfWidth));
136  }
137  }
139  kernelPtr(new afwMath::FixedKernel(image));
140  kernelBasisList.push_back(kernelPtr);
141  polynomial.setParameter(n, 0.);
142  }
143  }
144  }
145  return renormalizeKernelList(kernelBasisList);
146  }
147 
148 
149  Eigen::MatrixXd makeRegularizationMatrix(
151  ) {
152 
153  /* NOTES
154  *
155  * The 3-point first derivative central difference (Laplacian) yields
156  * diagonal stripes and should not be used.
157 
158  coeffs[0][1] = -1. / 2.;
159  coeffs[1][0] = -1. / 2.;
160  coeffs[1][2] = 1. / 2.;
161  coeffs[2][1] = 1. / 2.;
162 
163  * The 5-point second derivative central difference (Laplacian) looks great.
164  * For smaller lambdas you need a higher border penalty. In general, if you
165  * decrease the regularization strength you should increase the border
166  * penalty to avoid noise in the border pixels. This has been used to value
167  * 10 and things still look OK.
168 
169  * The 9-point second derivative central difference (Laplacian with off
170  * diagonal terms) also looks great. Seems to have slightly higher-valued
171  * border pixels so make boundary larger if using this. E.g. 1.5.
172 
173  * The forward finite difference, first derivative term works good
174  *
175  * The forward finite difference, second derivative term is slightly banded
176  * in LLC
177  *
178  * The forward finite difference, third derivative term is highly banded in
179  * LLC and should not be used.
180  *
181  */
182 
183  std::string regularizationType = ps.getAsString("regularizationType");
184  int width = ps.getAsInt("kernelSize");
185  int height = ps.getAsInt("kernelSize");
186  float borderPenalty = ps.getAsDouble("regularizationBorderPenalty");
187  bool fitForBackground = ps.getAsBool("fitForBackground");
188 
189  Eigen::MatrixXd bMat;
190  if (regularizationType == "centralDifference") {
191  int stencil = ps.getAsInt("centralRegularizationStencil");
192  bMat = makeCentralDifferenceMatrix(width, height, stencil, borderPenalty, fitForBackground);
193  }
194  else if (regularizationType == "forwardDifference") {
195  std::vector<int> orders = ps.getArray<int>("forwardRegularizationOrders");
196  bMat = makeForwardDifferenceMatrix(width, height, orders, borderPenalty, fitForBackground);
197  }
198  else {
199  throw LSST_EXCEPT(pexExcept::Exception, "regularizationType not recognized");
200  }
201 
202  Eigen::MatrixXd hMat = bMat.transpose() * bMat;
203  return hMat;
204  }
205 
210  int width,
211  int height,
212  int stencil,
213  float borderPenalty,
214  bool fitForBackground
215  ) {
216 
217  /* 5- or 9-point stencil to approximate the Laplacian; i.e. this is a second
218  * order central finite difference.
219  *
220  * 5-point approximation ignores off-diagonal elements, and is
221  *
222  * f(x-1,y) + f(x+1,y) + f(x,y-1) + f(x,y+1) - 4 f(x,y)
223  *
224  * 0 1 0
225  * 1 -4 1
226  * 0 1 0
227  *
228  *
229  * 9-point approximation includes diagonals and is
230  *
231  * 1 4 1
232  * 4 -20 4 / 6
233  * 1 4 1
234  *
235  */
236 
237  if (borderPenalty < 0)
238  throw LSST_EXCEPT(pexExcept::Exception, "Only border penalty of >= 0 allowed");
239 
241  coeffs(3, std::vector<float>(3,0));
242 
243  if (stencil == 5) {
244  /* http://www.physics.arizona.edu/~restrepo/475B/Notes/source/node51.html
245  *
246  * This is equivalent to a second order central difference summed along
247  * the x-axis, and then summed along the y-axis.
248  *
249  * http://www.holoborodko.com/pavel/?page_id=239
250  *
251  */
252  coeffs[0][1] = 1.;
253  coeffs[1][0] = 1.;
254  coeffs[1][1] = -4.;
255  coeffs[1][2] = 1.;
256  coeffs[2][1] = 1.;
257  }
258  else if (stencil == 9) {
259  /* http://www.physics.arizona.edu/~restrepo/475B/Notes/source/node52.html */
260  coeffs[0][0] = 1. / 6.;
261  coeffs[0][1] = 4. / 6.;
262  coeffs[0][2] = 1. / 6.;
263  coeffs[1][0] = 4. / 6.;
264  coeffs[1][1] = -20. / 6.;
265  coeffs[1][2] = 4. / 6.;
266  coeffs[2][0] = 1. / 6.;
267  coeffs[2][1] = 4. / 6.;
268  coeffs[2][2] = 1. / 6.;
269  }
270  else {
271  throw LSST_EXCEPT(pexExcept::Exception, "Only 5- or 9-point Laplacian stencils allowed");
272  }
273 
274  int nBgTerms = fitForBackground ? 1 : 0;
275  Eigen::MatrixXd bMat = Eigen::MatrixXd::Zero(width * height + nBgTerms, width * height + nBgTerms);
276 
277  for (int i = 0; i < width*height; i++) {
278  int const x0 = i % width; // the x coord in the kernel image
279  int const y0 = i / width; // the y coord in the kernel image
280  int const distX = width - x0 - 1; // distance from edge of image
281  int const distY = height - y0 - 1; // distance from edge of image
282 
283  if ( (x0 > 0) && (y0 > 0) && (distX > 0) && (distY > 0) ) {
284  for (int dx = -1; dx < 2; dx += 1) {
285  for (int dy = -1; dy < 2; dy += 1) {
286  bMat(i, i + dx + dy * width) += coeffs[dx+1][dy+1];
287  }
288  }
289  }
290  else {
291  bMat(i, i) = borderPenalty;
292  }
293  }
294 
295  if (fitForBackground) {
296  /* Last row / col should have no regularization since its the background term */
297  if (bMat.col(width*height).sum() != 0.) {
298  throw LSST_EXCEPT(pexExcept::Exception, "Error 1 in regularization matrix");
299  }
300  if (bMat.row(width*height).sum() != 0.) {
301  throw LSST_EXCEPT(pexExcept::Exception, "Error 2 in regularization matrix");
302  }
303  }
304 
305  return bMat;
306  }
307 
312  int width,
313  int height,
314  std::vector<int> const& orders,
315  float borderPenalty,
316  bool fitForBackground
317  ) {
318 
319  /*
320  Instead of Taylor expanding the forward difference approximation of
321  derivatives (N.R. section 18.5) lets just hard code in the expansion of
322  the 1st through 3rd derivatives, which will try and enforce smoothness of
323  0 through 2nd derivatives.
324 
325  A property of the basic "finite difference regularization" is that their
326  rows (column multipliers) sum to 0.
327 
328  We taper the order of the constraint as you get close to the boundary.
329  The actual perimeter values are left unconstrained but we might want to
330  consider giving these the same penalties as the other border pixels,
331  which is +1 (since the value gets squared).
332 
333  */
334 
335  if (borderPenalty < 0)
336  throw LSST_EXCEPT(pexExcept::Exception, "Only border penalty of >= 0 allowed");
337 
339  coeffs(4, std::vector<float>(4,0));
340 
341  // penalize border? this is along the diagonal and gets squared, so sign does not matter
342  coeffs[0][0] = borderPenalty;
343 
344  // penalize zeroth derivative
345  coeffs[1][0] = -1.;
346  coeffs[1][1] = +1.;
347 
348  // penalize first derivative
349  coeffs[2][0] = -1.;
350  coeffs[2][1] = +2.;
351  coeffs[2][2] = -1.;
352 
353  // penalize second derivative
354  coeffs[3][0] = -1.;
355  coeffs[3][1] = +3.;
356  coeffs[3][2] = -3.;
357  coeffs[3][3] = +1.;
358 
359  int nBgTerms = fitForBackground ? 1 : 0;
360  Eigen::MatrixXd bTot = Eigen::MatrixXd::Zero(width * height + nBgTerms, width * height + nBgTerms);
361 
363  for (order = orders.begin(); order != orders.end(); order++) {
364  if ((*order < 1) || (*order > 3))
365  throw LSST_EXCEPT(pexExcept::Exception, "Only orders 1..3 allowed");
366 
367  Eigen::MatrixXd bMatX = Eigen::MatrixXd::Zero(width * height + nBgTerms,
368  width * height + nBgTerms);
369  Eigen::MatrixXd bMatY = Eigen::MatrixXd::Zero(width * height + nBgTerms,
370  width * height + nBgTerms);
371 
372  for (int i = 0; i < width*height; i++) {
373  int const x0 = i % width; // the x coord in the kernel image
374  int const y0 = i / width; // the y coord in the kernel image
375 
376  int distX = width - x0 - 1; // distance from edge of image
377  int orderToUseX = std::min(distX, *order);
378  for (int j = 0; j < orderToUseX+1; j++) {
379  bMatX(i, i + j) = coeffs[orderToUseX][j];
380  }
381 
382  int distY = height - y0 - 1; // distance from edge of image
383  int orderToUseY = std::min(distY, *order);
384  for (int j = 0; j < orderToUseY+1; j++) {
385  bMatY(i, i + j * width) = coeffs[orderToUseY][j];
386  }
387  }
388  bTot += bMatX;
389  bTot += bMatY;
390  }
391 
392  if (fitForBackground) {
393  /* Last row / col should have no regularization since its the background term */
394  if (bTot.col(width*height).sum() != 0.) {
395  throw LSST_EXCEPT(pexExcept::Exception, "Error in regularization matrix");
396  }
397  if (bTot.row(width*height).sum() != 0.) {
398  throw LSST_EXCEPT(pexExcept::Exception, "Error in regularization matrix");
399  }
400  }
401 
402  return bTot;
403  }
404 
405 
415  lsst::afw::math::KernelList const &kernelListIn
416  ) {
418  typedef afwImage::Image<Pixel> Image;
419  double kSum;
420 
421  /*
422 
423  We want all the bases except for the first to sum to 0.0. This allows
424  us to achieve kernel flux conservation (Ksum) across the image since all
425  the power will be in the first term, which will not vary spatially.
426 
427  K(x,y) = Ksum * B_0 + Sum_i : a(x,y) * B_i
428 
429  To do this, normalize all Kernels to sum = 1. and subtract B_0 from all
430  subsequent kenrels.
431 
432  To get an idea of the relative contribution of each of these basis
433  functions later on down the line, lets also normalize them such that
434 
435  Sum(B_i) == 0.0 *and*
436  B_i * B_i == 1.0
437 
438  For completeness
439 
440  Sum(B_0) == 1.0
441  B_0 * B_0 != 1.0
442 
443  */
444  afwMath::KernelList kernelListOut;
445  if (kernelListIn.size() == 0) {
446  return kernelListOut;
447  }
448 
449  Image image0(kernelListIn[0]->getDimensions());
450  for (unsigned int i = 0; i < kernelListIn.size(); i++) {
451  if (i == 0) {
452  /* Make sure that it is normalized to kSum 1. */
453  (void)kernelListIn[i]->computeImage(image0, true);
455  kernelPtr(new afwMath::FixedKernel(image0));
456  kernelListOut.push_back(kernelPtr);
457 
458  continue;
459  }
460 
461  /* Don't normalize here */
462  Image image(kernelListIn[i]->getDimensions());
463  (void)kernelListIn[i]->computeImage(image, false);
464  /* image.writeFits(str(boost::format("in_k%d.fits") % i)); */
465 
466  /* Check the kernel sum; if its close to zero don't do anything */
467  kSum = 0.;
468  for (int y = 0; y < image.getHeight(); y++) {
469  for (Image::xy_locator ptr = image.xy_at(0, y), end = image.xy_at(image.getWidth(), y);
470  ptr != end; ++ptr.x()) {
471  kSum += *ptr;
472  }
473  }
474 
475  /* std::numeric_limits<float>::epsilon() ~ e-7
476  std::numeric_limits<double>::epsilon() ~ e-16
477 
478  If we end up with 2e-16 kernel sum, this still blows up the kernel values.
479  Even though the kernels are double, use the float limits instead
480  */
481  if (fabs(kSum) > std::numeric_limits<float>::epsilon()) {
482  image /= kSum;
483  image -= image0;
484  }
485 
486  /* Finally, rescale such that the inner product is 1 */
487  kSum = 0.;
488  for (int y = 0; y < image.getHeight(); y++) {
489  for (Image::xy_locator ptr = image.xy_at(0, y), end = image.xy_at(image.getWidth(), y);
490  ptr != end; ++ptr.x()) {
491  kSum += *ptr * *ptr;
492  }
493  }
494  image /= std::sqrt(kSum);
495  /* image.writeFits(str(boost::format("out_k%d.fits") % i)); */
496 
498  kernelPtr(new afwMath::FixedKernel(image));
499  kernelListOut.push_back(kernelPtr);
500  }
501  return kernelListOut;
502  }
503 
504 
505 
510  unsigned int width,
511  unsigned int height,
512  unsigned int order,
513  unsigned int boundary_style, // 0 = unwrapped, 1 = wrapped, 2 = order-tapered
514  unsigned int difference_style, // 0 = forward, 1 = central
515  bool printB // a debug flag ... remove when done.
516  ) {
517 
518  if (order > 2) throw LSST_EXCEPT(pexExcept::Exception, "Only orders 0..2 allowed");
519 
520  if (boundary_style > 2) {
521  throw LSST_EXCEPT(pexExcept::Exception, "Boundary styles 0..2 defined");
522  }
523  if (difference_style > 1) {
524  throw LSST_EXCEPT(pexExcept::Exception, "Only forward(0), and central(1) difference types defined");
525  }
526 
527  /* what works, and what doesn't */
528  // == good job ==
529  // - order 0, wrapped, forward
530  // - order 1, wrapped or tapered, central or forward
531  // - order 2, wrapped or tapered, forward
532  // == bad job (usually diagongal stripes) ==
533  // - all others
534 
535 
536  /*
537  Instead of Taylor expanding the forward difference approximation of
538  derivatives (N.R. section 18.5) lets just hard code in the expansion of
539  the 1st through 3rd derivatives, which will try and enforce smoothness of
540  0 through 2nd derivatives.
541 
542  A property of the basic "finite difference regularization" is that their
543  rows (column multipliers) sum to 0.
544 
545  Another consideration is to use *multiple* finite difference operators as
546  a constraint.
547 
548  */
549 
550 
551  // ===========================================================================
552  // Get the coeffs for the finite differencing
553  // note: The coeffs are stored 2D although they are essentially 1D entities.
554  // The 2d design was chosen to allow cross-terms to be included,
555  // though they are not yet implemented.
556  //
558  coeffs(3, std::vector<std::vector<float> >(5, std::vector<float>(5,0)));
559  unsigned int x_cen = 0, y_cen = 0; // center of reqested order coeffs
560  unsigned int x_cen1 = 0, y_cen1 = 0; // center of order 1 coeffs
561  unsigned int x_cen2 = 0, y_cen2 = 0; // center of order 2 coeffs
562  unsigned int x_size = 0, y_size = 0;
563 
564  // forward difference coefficients
565  if (difference_style == 0) {
566 
567  y_cen = x_cen = 0;
568  x_cen1 = y_cen1 = 0;
569  x_cen2 = y_cen2 = 0;
570 
571  x_size = y_size = order + 2;
572 
573  // default forward difference suggested in NR chap 18
574  // 0th order
575  coeffs[0][0][0] = -2;
576  coeffs[0][0][1] = 1;
577  coeffs[0][1][0] = 1;
578  coeffs[0][1][1] = 0;
579 
580  // 1st 2
581  coeffs[1][0][0] = -2;
582  coeffs[1][0][1] = 2;
583  coeffs[1][0][2] = -1;
584  coeffs[1][1][0] = 2;
585  coeffs[1][1][1] = 0;
586  coeffs[1][1][2] = 0;
587  coeffs[1][2][0] = -1;
588  coeffs[1][2][1] = 0;
589  coeffs[1][2][2] = 0;
590 
591  // 2nd 2
592  coeffs[2][0][0] = -2;
593  coeffs[2][0][1] = 3;
594  coeffs[2][0][2] = -3;
595  coeffs[2][0][3] = 1;
596  coeffs[2][1][0] = 3;
597  coeffs[2][1][1] = 0;
598  coeffs[2][1][2] = 0;
599  coeffs[2][1][3] = 0;
600  coeffs[2][2][0] = -3;
601  coeffs[2][2][1] = 0;
602  coeffs[2][2][2] = 0;
603  coeffs[2][2][3] = 0;
604  coeffs[2][3][0] = 1;
605  coeffs[2][3][1] = 0;
606  coeffs[2][3][2] = 0;
607  coeffs[2][3][3] = 0;
608  }
609 
610  // central difference coefficients
611  if (difference_style == 1) {
612 
613  // this is asymmetric and produces diagonal banding in the kernel
614  // from: http://www.holoborodko.com/pavel/?page_id=239
615  if (order == 0) {
616  y_cen = x_cen = 1;
617  x_size = y_size = 3;
618  }
619  coeffs[0][0][0] = 0;
620  coeffs[0][0][1] = -1;
621  coeffs[0][0][2] = 0;
622 
623  coeffs[0][1][0] = -1;
624  coeffs[0][1][1] = 0;
625  coeffs[0][1][2] = 1;
626 
627  coeffs[0][2][0] = 0;
628  coeffs[0][2][1] = 1;
629  coeffs[0][2][2] = 0;
630 
631 
632  // this works well and is largely the same as order=1 forward-diff.
633  // from: http://www.holoborodko.com/pavel/?page_id=239
634  if (order == 1) {
635  y_cen = x_cen = 1;
636  x_size = y_size = 3;
637  }
638  y_cen1 = x_cen1 = 1;
639  coeffs[1][0][0] = 0;
640  coeffs[1][0][1] = 1;
641  coeffs[1][0][2] = 0;
642 
643  coeffs[1][1][0] = 1;
644  coeffs[1][1][1] = -4;
645  coeffs[1][1][2] = 1;
646 
647  coeffs[1][2][0] = 0;
648  coeffs[1][2][1] = 1;
649  coeffs[1][2][2] = 0;
650 
651 
652  // asymmetric and produces diagonal banding in the kernel
653  // from http://www.holoborodko.com/pavel/?page_id=239
654  if (order == 2) {
655  y_cen = x_cen = 2;
656  x_size = y_size = 5;
657  }
658  y_cen2 = x_cen2 = 2;
659  coeffs[2][0][0] = 0;
660  coeffs[2][0][1] = 0;
661  coeffs[2][0][2] = -1;
662  coeffs[2][0][3] = 0;
663  coeffs[2][0][4] = 0;
664 
665  coeffs[2][1][0] = 0;
666  coeffs[2][1][1] = 0;
667  coeffs[2][1][2] = 2;
668  coeffs[2][1][3] = 0;
669  coeffs[2][1][4] = 0;
670 
671  coeffs[2][2][0] = -1;
672  coeffs[2][2][1] = 2;
673  coeffs[2][2][2] = 0;
674  coeffs[2][2][3] = -2;
675  coeffs[2][2][4] = 1;
676 
677  coeffs[2][3][0] = 0;
678  coeffs[2][3][1] = 0;
679  coeffs[2][3][2] = -2;
680  coeffs[2][3][3] = 0;
681  coeffs[2][3][4] = 0;
682 
683  coeffs[2][4][0] = 0;
684  coeffs[2][4][1] = 0;
685  coeffs[2][4][2] = 1;
686  coeffs[2][4][3] = 0;
687  coeffs[2][4][4] = 0;
688  }
689 
690 
691  /* Note we have to add 1 extra (empty) term here because of the differential
692  * background fitting */
693  Eigen::MatrixXd bMat = Eigen::MatrixXd::Zero(width*height+1, width*height+1);
694 
695  /* Forward difference approximation */
696  for (unsigned int i = 0; i < width*height; i++) {
697 
698  unsigned int const x0 = i % width; // the x coord in the kernel image
699  unsigned int const y0 = i / width; // the y coord in the kernel image
700 
701  unsigned int x_edge_distance = (x0 > (width - x0 - 1)) ? width - x0 - 1 : x0;
702  unsigned int y_edge_distance = (y0 > (height - y0 - 1)) ? height - y0 - 1 : y0;
703  unsigned int edge_distance = (x_edge_distance < y_edge_distance) ? x_edge_distance :
704  y_edge_distance;
705 
706  for (unsigned int dx = 0; dx < x_size; dx++) {
707  for (unsigned int dy = 0; dy < y_size; dy++) {
708 
709  // determine where to put this coeff
710 
711  // handle the boundary condition
712  // note: adding width and height in the sum prevents negatives
713  unsigned int x = 0;
714  unsigned int y = 0;
715  double this_coeff = 0;
716 
717  // no-wrapping at edges
718  if (boundary_style == 0) {
719  x = x0 + dx - x_cen;
720  y = y0 + dy - y_cen;
721  if (y > height - 1 || x > width - 1) {
722  continue;
723  }
724  this_coeff = coeffs[order][dx][dy];
725 
726  // wrapping at edges
727  } else if (boundary_style == 1) {
728  x = (width + x0 + dx - x_cen) % width;
729  y = (height + y0 + dy - y_cen) % height;
730  this_coeff = coeffs[order][dx][dy];
731 
732  // order tapering to the edge (just clone wrapping for now)
733  // - use the lowest order possible
734  } else if (boundary_style == 2) {
735 
736  // edge rows and columns ... set to constant
737  if (edge_distance == 0) {
738  x = x0;
739  y = y0;
740  this_coeff = 1;
741  }
742  // in one from edge, use 1st order
743  else if (edge_distance == 1 && order > 0) {
744  x = (width + x0 + dx - x_cen1) % width;
745  y = (height + y0 + dy - y_cen1) % height;
746  if ((dx < 3) && (dy < 3)) { this_coeff = coeffs[1][dx][dy]; }
747  }
748  // in two from edge, use 2st order if order > 1
749  else if (edge_distance == 2 && order > 1){
750  x = (width + x0 + dx - x_cen2) % width;
751  y = (height + y0 + dy - y_cen2) % height;
752  if ((dx < 5) && (dy < 5)) { this_coeff = coeffs[2][dx][dy]; }
753  }
754  // if we're somewhere in the middle
755  else if (edge_distance > order) {
756  x = (width + x0 + dx - x_cen) % width;
757  y = (height + y0 + dy - y_cen) % height;
758  this_coeff = coeffs[order][dx][dy];
759  }
760 
761  }
762 
763  bMat(i, y*width + x) = this_coeff;
764 
765  }
766 
767  }
768 
769  }
770 
771  if (printB) {
772  std::cout << bMat << std::endl;
773  }
774 
775  Eigen::MatrixXd hMat = bMat.transpose() * bMat;
776  return hMat;
777  }
778 
779 }}} // end of namespace lsst::ip::diffim
y
int y
Definition: SpanSet.cc:49
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
lsst::daf::base::PropertySet::getAsInt
int getAsInt(std::string const &name) const
Get the last value for a bool/char/short/int property name (possibly hierarchical).
lsst::daf::base::PropertySet::getAsBool
bool getAsBool(std::string const &name) const
Get the last value for a bool property name (possibly hierarchical).
std::string
STL class.
std::shared_ptr
STL class.
lsst::ip::diffim::makeRegularizationMatrix
Eigen::MatrixXd makeRegularizationMatrix(lsst::daf::base::PropertySet const &ps)
Build a regularization matrix for Delta function kernels.
Definition: BasisLists.cc:149
lsst::afw::math::DeltaFunctionKernel
A kernel that has only one non-zero pixel (of value 1)
Definition: Kernel.h:644
lsst::meas::modelfit::Pixel
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
std::vector< std::shared_ptr< Kernel > >
std::vector::size
T size(T... args)
lsst::afw::math::FixedKernel
A kernel created from an Image.
Definition: Kernel.h:472
lsst::afw::math::AnalyticKernel::computeImage
double computeImage(lsst::afw::image::Image< Pixel > &image, bool doNormalize, double x=0.0, double y=0.0) const
Compute an image (pixellized representation of the kernel) in place.
Definition: AnalyticKernel.cc:82
lsst::afw::math::GaussianFunction2
2-dimensional Gaussian
Definition: FunctionLibrary.h:201
lsst::ip::diffim::makeFiniteDifferenceRegularizationDeprecated
Eigen::MatrixXd makeFiniteDifferenceRegularizationDeprecated(unsigned int width, unsigned int height, unsigned int order, unsigned int boundary_style, unsigned int difference_style, bool printB)
Generate regularization matrix for delta function kernels.
Definition: BasisLists.cc:509
std::sqrt
T sqrt(T... args)
end
int end
Definition: BoundedField.cc:105
std::vector::push_back
T push_back(T... args)
math.h
image
afw::table::Key< afw::table::Array< ImagePixelT > > image
Definition: HeavyFootprint.cc:216
lsst::ip::diffim::makeDeltaFunctionBasisList
lsst::afw::math::KernelList makeDeltaFunctionBasisList(int width, int height)
Build a set of Delta Function basis kernels.
Definition: BasisLists.cc:47
std::cout
x
double x
Definition: ChebyshevBoundedField.cc:277
lsst::daf::base::PropertySet::getAsString
std::string getAsString(std::string const &name) const
Get the last value for a string property name (possibly hierarchical).
PropertySet.h
BasisLists.h
Subroutines associated with generating, normalising, and regularising Basis functions.
ptr
uint64_t * ptr
Definition: RangeSet.cc:88
image.h
std::numeric_limits::epsilon
T epsilon(T... args)
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
lsst::daf::base::PropertySet::getAsDouble
double getAsDouble(std::string const &name) const
Get the last value for any arithmetic property name (possibly hierarchical).
std::min
T min(T... args)
lsst::ip::diffim::makeCentralDifferenceMatrix
Eigen::MatrixXd makeCentralDifferenceMatrix(int width, int height, int stencil, float borderPenalty, bool fitForBackground)
Build a central difference Laplacian regularization matrix for Delta function kernels.
Definition: BasisLists.cc:209
lsst::geom
Definition: AffineTransform.h:36
lsst::afw::math::AnalyticKernel
A kernel described by a function.
Definition: Kernel.h:536
std::endl
T endl(T... args)
lsst::afw::math::Function::setParameter
void setParameter(unsigned int ind, double newValue)
Set one function parameter without range checking.
Definition: Function.h:143
lsst::ip::diffim::makeAlardLuptonBasisList
lsst::afw::math::KernelList makeAlardLuptonBasisList(int halfWidth, int nGauss, std::vector< double > const &sigGauss, std::vector< int > const &degGauss)
Build a set of Alard/Lupton basis kernels.
Definition: BasisLists.cc:78
row
int row
Definition: CR.cc:145
LOGL_DEBUG
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
std::vector::begin
T begin(T... args)
col
int col
Definition: CR.cc:144
lsst::afw::math
Definition: statistics.dox:6
lsst::geom::Point< int, 2 >
lsst::daf::base::PropertySet
Class for storing generic metadata.
Definition: PropertySet.h:67
lsst.pex::exceptions
Definition: Exception.h:37
lsst.pex::exceptions::Exception
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
std::vector::end
T end(T... args)
lsst::afw::math::PolynomialFunction2
2-dimensional polynomial function with cross terms
Definition: FunctionLibrary.h:449
Exception.h
lsst::afw::image::Image< Pixel >
lsst::ip::diffim::renormalizeKernelList
lsst::afw::math::KernelList renormalizeKernelList(lsst::afw::math::KernelList const &kernelListIn)
Renormalize a list of basis kernels.
Definition: BasisLists.cc:414
lsst::geom::Extent< int, 2 >
Log.h
LSST DM logging module built on log4cxx.
lsst::ip::diffim::makeForwardDifferenceMatrix
Eigen::MatrixXd makeForwardDifferenceMatrix(int width, int height, std::vector< int > const &orders, float borderPenalty, bool fitForBackground)
Build a forward difference regularization matrix for Delta function kernels.
Definition: BasisLists.cc:311
lsst::afw::math::Kernel::Pixel
double Pixel
Definition: Kernel.h:113
geom.h
lsst::daf::base::PropertySet::getArray
std::vector< T > getArray(std::string const &name) const
Get the vector of values for a property name (possibly hierarchical).