17 #include "boost/timer.hpp" 20 #include "Eigen/Cholesky" 23 #include "Eigen/Eigenvalues" 26 #include "lsst/afw/math.h" 27 #include "lsst/afw/geom.h" 28 #include "lsst/afw/image.h" 29 #include "lsst/afw/detection.h" 30 #include "lsst/log/Log.h" 31 #include "lsst/pex/exceptions/Runtime.h" 37 #include "ndarray/eigen.h" 39 #define DEBUG_MATRIX 0 40 #define DEBUG_MATRIX2 0 42 namespace afwDet = lsst::afw::detection;
43 namespace afwMath = lsst::afw::math;
44 namespace afwGeom = lsst::afw::geom;
45 namespace afwImage = lsst::afw::image;
46 namespace pexExcept = lsst::pex::exceptions;
65 _fitForBackground(fitForBackground)
98 switch (conditionType) {
101 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(mMat);
102 Eigen::VectorXd eValues = eVecValues.eigenvalues();
103 double eMax = eValues.maxCoeff();
104 double eMin = eValues.minCoeff();
105 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.getConditionNumber",
106 "EIGENVALUE eMax / eMin = %.3e", eMax / eMin);
107 return (eMax / eMin);
112 Eigen::VectorXd sValues = mMat.jacobiSvd().singularValues();
113 double sMax = sValues.maxCoeff();
114 double sMin = sValues.minCoeff();
115 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.getConditionNumber",
116 "SVD eMax / eMin = %.3e", sMax / sMin);
117 return (sMax / sMin);
122 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
123 "Undefined ConditionNumberType : only EIGENVALUE, SVD allowed.");
130 Eigen::VectorXd
const& bVec) {
133 std::cout <<
"M " << std::endl;
134 std::cout << mMat << std::endl;
135 std::cout <<
"B " << std::endl;
136 std::cout << bVec << std::endl;
139 Eigen::VectorXd aVec = Eigen::VectorXd::Zero(bVec.size());
144 LOGL_DEBUG(
"TRACE2.ip.diffim.KernelSolution.solve",
145 "Solving for kernel");
147 Eigen::FullPivLU<Eigen::MatrixXd> lu(mMat);
148 if (lu.isInvertible()) {
149 aVec = lu.solve(bVec);
151 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
152 "Unable to determine kernel via LU");
157 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(mMat);
158 Eigen::MatrixXd
const& rMat = eVecValues.eigenvectors();
159 Eigen::VectorXd eValues = eVecValues.eigenvalues();
161 for (
int i = 0; i != eValues.rows(); ++i) {
162 if (eValues(i) != 0.0) {
163 eValues(i) = 1.0/eValues(i);
167 aVec = rMat * eValues.asDiagonal() * rMat.transpose() * bVec;
168 }
catch (pexExcept::Exception& e) {
171 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
172 "Unable to determine kernel via eigen-values");
174 throw LSST_EXCEPT(pexExcept::Exception,
"Unable to determine kernel solution");
178 double time = t.elapsed();
179 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
180 "Compute time for matrix math : %.2f s", time);
183 std::cout <<
"A " << std::endl;
184 std::cout << aVec << std::endl;
192 template <
typename InputT>
194 lsst::afw::math::KernelList
const& basisList,
195 bool fitForBackground
206 std::vector<double> kValues(basisList.size());
207 _kernel = std::shared_ptr<afwMath::Kernel>(
208 new afwMath::LinearCombinationKernel(basisList, kValues)
212 template <
typename InputT>
215 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return solution");
220 template <
typename InputT>
223 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return image");
225 std::shared_ptr<afwImage::Image<afwMath::Kernel::Pixel>> image(
226 new afwImage::Image<afwMath::Kernel::Pixel>(
_kernel->getDimensions())
228 (void)
_kernel->computeImage(*image,
false);
232 template <
typename InputT>
235 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return background");
240 template <
typename InputT>
243 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return ksum");
248 template <
typename InputT>
249 std::pair<std::shared_ptr<lsst::afw::math::Kernel>,
double>
252 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return solution");
258 template <
typename InputT>
260 lsst::afw::image::Image<InputT>
const &templateImage,
261 lsst::afw::image::Image<InputT>
const &scienceImage,
262 lsst::afw::image::Image<lsst::afw::image::VariancePixel>
const &varianceEstimate
265 afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
266 if (varStats.getValue(afwMath::MIN) < 0.0) {
267 throw LSST_EXCEPT(pexExcept::Exception,
268 "Error: variance less than 0.0");
270 if (varStats.getValue(afwMath::MIN) == 0.0) {
271 throw LSST_EXCEPT(pexExcept::Exception,
272 "Error: variance equals 0.0, cannot inverse variance weight");
275 lsst::afw::math::KernelList basisList =
276 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(
_kernel)->getKernelList();
278 unsigned int const nKernelParameters = basisList.size();
280 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
282 std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
316 afwGeom::Box2I goodBBox = (*kiter)->shrinkBBox(templateImage.getBBox(afwImage::LOCAL));
317 unsigned int const startCol = goodBBox.getMinX();
318 unsigned int const startRow = goodBBox.getMinY();
320 unsigned int endCol = goodBBox.getMaxX() + 1;
321 unsigned int endRow = goodBBox.getMaxY() + 1;
336 startRow, startCol, endRow-startRow, endCol-startCol
337 ).array().inverse().matrix();
340 eigenTemplate.resize(eigenTemplate.rows()*eigenTemplate.cols(), 1);
341 eigenScience.resize(eigenScience.rows()*eigenScience.cols(), 1);
342 eigeniVariance.resize(eigeniVariance.rows()*eigeniVariance.cols(), 1);
345 afwImage::Image<PixelT> cimage(templateImage.getDimensions());
348 std::vector<Eigen::MatrixXd> convolvedEigenList(nKernelParameters);
351 typename std::vector<Eigen::MatrixXd>::iterator eiter = convolvedEigenList.begin();
353 for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
354 afwMath::convolve(cimage, templateImage, **kiter,
false);
360 cMat.resize(cMat.size(), 1);
365 double time = t.elapsed();
366 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
367 "Total compute time to do basis convolutions : %.2f s", time);
374 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
375 typename std::vector<Eigen::MatrixXd>::iterator eiterj = convolvedEigenList.begin();
376 typename std::vector<Eigen::MatrixXd>::iterator eiterE = convolvedEigenList.end();
377 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
378 cMat.col(kidxj) = eiterj->col(0);
382 cMat.col(nParameters-1).fill(1.);
385 _ivVec = eigeniVariance.col(0);
386 _iVec = eigenScience.col(0);
393 template <
typename InputT>
395 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.solve",
396 "mMat is %d x %d; bVec is %d; cMat is %d x %d; vVec is %d; iVec is %d",
401 std::cout <<
"C" << std::endl;
402 std::cout <<
_cMat << std::endl;
403 std::cout <<
"iV" << std::endl;
404 std::cout <<
_ivVec << std::endl;
405 std::cout <<
"I" << std::endl;
406 std::cout <<
_iVec << std::endl;
411 }
catch (pexExcept::Exception &e) {
412 LSST_EXCEPT_ADD(e,
"Unable to solve static kernel matrix");
419 template <
typename InputT>
422 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot make solution");
425 unsigned int const nParameters =
_aVec.size();
427 unsigned int const nKernelParameters =
428 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(
_kernel)->getKernelList().size();
429 if (nParameters != (nKernelParameters + nBackgroundParameters))
430 throw LSST_EXCEPT(pexExcept::Exception,
"Mismatched sizes in kernel solution");
433 std::vector<double> kValues(nKernelParameters);
434 for (
unsigned int idx = 0; idx < nKernelParameters; idx++) {
435 if (std::isnan(
_aVec(idx))) {
436 throw LSST_EXCEPT(pexExcept::Exception,
437 str(boost::format(
"Unable to determine kernel solution %d (nan)") % idx));
439 kValues[idx] =
_aVec(idx);
441 _kernel->setKernelParameters(kValues);
443 std::shared_ptr<ImageT> image (
449 if (std::isnan(
_aVec(nParameters-1))) {
450 throw LSST_EXCEPT(pexExcept::Exception,
451 str(boost::format(
"Unable to determine background solution %d (nan)") %
459 template <
typename InputT>
461 throw LSST_EXCEPT(pexExcept::Exception,
"Uncertainty calculation not supported");
489 template <
typename InputT>
491 lsst::afw::math::KernelList
const& basisList,
492 bool fitForBackground
497 template <
typename InputT>
499 lsst::afw::image::Image<InputT>
const &templateImage,
500 lsst::afw::image::Image<InputT>
const &scienceImage,
501 lsst::afw::image::Image<lsst::afw::image::VariancePixel>
const &varianceEstimate,
502 lsst::afw::image::Mask<lsst::afw::image::MaskPixel>
const &pixelMask
505 afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
506 if (varStats.getValue(afwMath::MIN) < 0.0) {
507 throw LSST_EXCEPT(pexExcept::Exception,
508 "Error: variance less than 0.0");
510 if (varStats.getValue(afwMath::MIN) == 0.0) {
511 throw LSST_EXCEPT(pexExcept::Exception,
512 "Error: variance equals 0.0, cannot inverse variance weight");
516 std::shared_ptr<afwDet::Footprint> fullFp(
517 new afwDet::Footprint(std::make_shared<afwGeom::SpanSet>(templateImage.getBBox())));
519 afwMath::KernelList basisList =
520 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->
_kernel)->getKernelList();
521 std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
524 afwImage::MaskPixel bitMask =
525 (afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"BAD") |
526 afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"SAT") |
527 afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"NO_DATA") |
528 afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"EDGE"));
531 afwDet::Threshold threshold = afwDet::Threshold(bitMask, afwDet::Threshold::BITMASK,
true);
532 afwDet::FootprintSet maskFpSet(pixelMask, threshold,
true);
535 int growPix = (*kiter)->getCtr().getX();
536 afwDet::FootprintSet maskedFpSetGrown(maskFpSet, growPix,
true);
539 for (
typename afwDet::FootprintSet::FootprintList::iterator
540 ptr = maskedFpSetGrown.getFootprints()->begin(),
541 end = maskedFpSetGrown.getFootprints()->end();
545 afwDet::setMaskFromFootprint(finalMask,
547 afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"BAD"));
551 afwImage::Mask<afwImage::MaskPixel> finalMask(pixelMask.getDimensions());
552 for (
auto const & foot : *(maskedFpSetGrown.getFootprints())) {
553 foot->getSpans()->setMask(finalMask, afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"BAD"));
555 pixelMask.writeFits(
"pixelmask.fits");
556 finalMask.writeFits(
"finalmask.fits");
559 ndarray::Array<int, 1, 1> maskArray =
560 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
561 fullFp->getSpans()->flatten(maskArray, finalMask.getArray(), templateImage.getXY0());
562 ndarray::EigenView<int, 1, 1> maskEigen(maskArray);
564 ndarray::Array<InputT, 1, 1> arrayTemplate =
565 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
566 fullFp->getSpans()->flatten(arrayTemplate, templateImage.getArray(), templateImage.getXY0());
567 ndarray::EigenView<InputT, 1, 1> eigenTemplate0(arrayTemplate);
569 ndarray::Array<InputT, 1, 1> arrayScience =
570 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
571 fullFp->getSpans()->flatten(arrayScience, scienceImage.getArray(), scienceImage.getXY0());
572 ndarray::EigenView<InputT, 1, 1> eigenScience0(arrayScience);
574 ndarray::Array<afwImage::VariancePixel, 1, 1> arrayVariance =
575 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
576 fullFp->getSpans()->flatten(arrayVariance, varianceEstimate.getArray(), varianceEstimate.getXY0());
577 ndarray::EigenView<afwImage::VariancePixel, 1, 1> eigenVariance0(arrayVariance);
580 for (
int i = 0; i < maskEigen.size(); i++) {
581 if (maskEigen(i) == 0.0)
585 Eigen::VectorXd eigenTemplate(nGood);
586 Eigen::VectorXd eigenScience(nGood);
587 Eigen::VectorXd eigenVariance(nGood);
589 for (
int i = 0; i < maskEigen.size(); i++) {
590 if (maskEigen(i) == 0.0) {
591 eigenTemplate(nUsed) = eigenTemplate0(i);
592 eigenScience(nUsed) = eigenScience0(i);
593 eigenVariance(nUsed) = eigenVariance0(i);
602 unsigned int const nKernelParameters = basisList.size();
604 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
607 afwImage::Image<InputT> cimage(templateImage.getDimensions());
610 std::vector<Eigen::VectorXd> convolvedEigenList(nKernelParameters);
613 typename std::vector<Eigen::VectorXd>::iterator eiter = convolvedEigenList.begin();
616 for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
617 afwMath::convolve(cimage, templateImage, **kiter,
false);
619 ndarray::Array<InputT, 1, 1> arrayC =
620 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
621 fullFp->getSpans()->flatten(arrayC, cimage.getArray(), cimage.getXY0());
622 ndarray::EigenView<InputT, 1, 1> eigenC0(arrayC);
624 Eigen::VectorXd eigenC(nGood);
626 for (
int i = 0; i < maskEigen.size(); i++) {
627 if (maskEigen(i) == 0.0) {
628 eigenC(nUsed) = eigenC0(i);
635 double time = t.elapsed();
636 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.buildWithMask",
637 "Total compute time to do basis convolutions : %.2f s", time);
641 Eigen::MatrixXd cMat(eigenTemplate.size(), nParameters);
642 typename std::vector<Eigen::VectorXd>::iterator eiterj = convolvedEigenList.begin();
643 typename std::vector<Eigen::VectorXd>::iterator eiterE = convolvedEigenList.end();
644 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
645 cMat.block(0, kidxj, eigenTemplate.size(), 1) =
646 Eigen::MatrixXd(*eiterj).block(0, 0, eigenTemplate.size(), 1);
650 cMat.col(nParameters-1).fill(1.);
653 this->
_ivVec = eigenVariance.array().inverse().matrix();
654 this->
_iVec = eigenScience;
662 template <
typename InputT>
664 lsst::afw::image::Image<InputT>
const &templateImage,
665 lsst::afw::image::Image<InputT>
const &scienceImage,
666 lsst::afw::image::Image<lsst::afw::image::VariancePixel>
const &varianceEstimate,
667 lsst::afw::image::Mask<lsst::afw::image::MaskPixel> pixelMask
670 afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
671 if (varStats.getValue(afwMath::MIN) < 0.0) {
672 throw LSST_EXCEPT(pexExcept::Exception,
673 "Error: variance less than 0.0");
675 if (varStats.getValue(afwMath::MIN) == 0.0) {
676 throw LSST_EXCEPT(pexExcept::Exception,
677 "Error: variance equals 0.0, cannot inverse variance weight");
680 lsst::afw::math::KernelList basisList =
681 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->
_kernel)->getKernelList();
682 std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
685 lsst::afw::image::Mask<lsst::afw::image::MaskPixel> sMask(pixelMask,
true);
686 afwImage::MaskPixel bitMask =
687 (afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"BAD") |
688 afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"SAT") |
689 afwImage::Mask<afwImage::MaskPixel>::getPlaneBitMask(
"EDGE"));
693 unsigned int const nKernelParameters = basisList.size();
695 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
702 afwGeom::Box2I shrunkLocalBBox = (*kiter)->shrinkBBox(templateImage.getBBox(afwImage::LOCAL));
703 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
704 "Limits of good pixels after convolution: %d,%d -> %d,%d (local)",
705 shrunkLocalBBox.getMinX(), shrunkLocalBBox.getMinY(),
706 shrunkLocalBBox.getMaxX(), shrunkLocalBBox.getMaxY());
709 unsigned int startCol = shrunkLocalBBox.getMinX();
710 unsigned int startRow = shrunkLocalBBox.getMinY();
711 unsigned int endCol = shrunkLocalBBox.getMaxX();
712 unsigned int endRow = shrunkLocalBBox.getMaxY();
735 startRow, startCol, endRow-startRow, endCol-startCol
736 ).array().inverse().matrix();
739 eMask.resize(eMask.rows()*eMask.cols(), 1);
740 eigenTemplate.resize(eigenTemplate.rows()*eigenTemplate.cols(), 1);
741 eigenScience.resize(eigenScience.rows()*eigenScience.cols(), 1);
742 eigeniVariance.resize(eigeniVariance.rows()*eigeniVariance.cols(), 1);
745 Eigen::MatrixXd maskedEigenTemplate(eigenTemplate.rows(), 1);
746 Eigen::MatrixXd maskedEigenScience(eigenScience.rows(), 1);
747 Eigen::MatrixXd maskedEigeniVariance(eigeniVariance.rows(), 1);
749 for (
int i = 0; i < eMask.rows(); i++) {
750 if (eMask(i, 0) == 0) {
751 maskedEigenTemplate(nGood, 0) = eigenTemplate(i, 0);
752 maskedEigenScience(nGood, 0) = eigenScience(i, 0);
753 maskedEigeniVariance(nGood, 0) = eigeniVariance(i, 0);
758 eigenTemplate = maskedEigenTemplate.block(0, 0, nGood, 1);
759 eigenScience = maskedEigenScience.block(0, 0, nGood, 1);
760 eigeniVariance = maskedEigeniVariance.block(0, 0, nGood, 1);
764 afwImage::Image<InputT> cimage(templateImage.getDimensions());
767 std::vector<Eigen::MatrixXd> convolvedEigenList(nKernelParameters);
770 typename std::vector<Eigen::MatrixXd>::iterator eiter = convolvedEigenList.begin();
772 for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
773 afwMath::convolve(cimage, templateImage, **kiter,
false);
779 cMat.resize(cMat.size(), 1);
782 Eigen::MatrixXd maskedcMat(cMat.rows(), 1);
784 for (
int i = 0; i < eMask.rows(); i++) {
785 if (eMask(i, 0) == 0) {
786 maskedcMat(nGood, 0) = cMat(i, 0);
790 cMat = maskedcMat.block(0, 0, nGood, 1);
794 double time = t.elapsed();
795 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
796 "Total compute time to do basis convolutions : %.2f s", time);
803 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
804 typename std::vector<Eigen::MatrixXd>::iterator eiterj = convolvedEigenList.begin();
805 typename std::vector<Eigen::MatrixXd>::iterator eiterE = convolvedEigenList.end();
806 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
807 cMat.col(kidxj) = eiterj->col(0);
811 cMat.col(nParameters-1).fill(1.);
814 this->
_ivVec = eigeniVariance.col(0);
815 this->
_iVec = eigenScience.col(0);
825 template <
typename InputT>
827 lsst::afw::image::Image<InputT>
const &templateImage,
828 lsst::afw::image::Image<InputT>
const &scienceImage,
829 lsst::afw::image::Image<lsst::afw::image::VariancePixel>
const &varianceEstimate,
830 lsst::afw::geom::Box2I maskBox
833 afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
834 if (varStats.getValue(afwMath::MIN) < 0.0) {
835 throw LSST_EXCEPT(pexExcept::Exception,
836 "Error: variance less than 0.0");
838 if (varStats.getValue(afwMath::MIN) == 0.0) {
839 throw LSST_EXCEPT(pexExcept::Exception,
840 "Error: variance equals 0.0, cannot inverse variance weight");
843 lsst::afw::math::KernelList basisList =
844 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->
_kernel)->getKernelList();
846 unsigned int const nKernelParameters = basisList.size();
848 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
850 std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
876 afwGeom::Box2I shrunkBBox = (*kiter)->shrinkBBox(templateImage.getBBox());
878 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
879 "Limits of good pixels after convolution: %d,%d -> %d,%d",
880 shrunkBBox.getMinX(), shrunkBBox.getMinY(),
881 shrunkBBox.getMaxX(), shrunkBBox.getMaxY());
883 unsigned int const startCol = shrunkBBox.getMinX();
884 unsigned int const startRow = shrunkBBox.getMinY();
885 unsigned int const endCol = shrunkBBox.getMaxX();
886 unsigned int const endRow = shrunkBBox.getMaxY();
905 int maskStartCol = maskBox.getMinX();
906 int maskStartRow = maskBox.getMinY();
907 int maskEndCol = maskBox.getMaxX();
908 int maskEndRow = maskBox.getMaxY();
929 afwGeom::Box2I tBox = afwGeom::Box2I(afwGeom::Point2I(startCol, maskEndRow + 1),
930 afwGeom::Point2I(endCol, endRow));
932 afwGeom::Box2I bBox = afwGeom::Box2I(afwGeom::Point2I(startCol, startRow),
933 afwGeom::Point2I(endCol, maskStartRow - 1));
935 afwGeom::Box2I lBox = afwGeom::Box2I(afwGeom::Point2I(startCol, maskStartRow),
936 afwGeom::Point2I(maskStartCol - 1, maskEndRow));
938 afwGeom::Box2I rBox = afwGeom::Box2I(afwGeom::Point2I(maskEndCol + 1, maskStartRow),
939 afwGeom::Point2I(endCol, maskEndRow));
941 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
942 "Upper good pixel region: %d,%d -> %d,%d",
943 tBox.getMinX(), tBox.getMinY(), tBox.getMaxX(), tBox.getMaxY());
944 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
945 "Bottom good pixel region: %d,%d -> %d,%d",
946 bBox.getMinX(), bBox.getMinY(), bBox.getMaxX(), bBox.getMaxY());
947 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
948 "Left good pixel region: %d,%d -> %d,%d",
949 lBox.getMinX(), lBox.getMinY(), lBox.getMaxX(), lBox.getMaxY());
950 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
951 "Right good pixel region: %d,%d -> %d,%d",
952 rBox.getMinX(), rBox.getMinY(), rBox.getMaxX(), rBox.getMaxY());
954 std::vector<afwGeom::Box2I> boxArray;
955 boxArray.push_back(tBox);
956 boxArray.push_back(bBox);
957 boxArray.push_back(lBox);
958 boxArray.push_back(rBox);
960 int totalSize = tBox.getWidth() * tBox.getHeight();
961 totalSize += bBox.getWidth() * bBox.getHeight();
962 totalSize += lBox.getWidth() * lBox.getHeight();
963 totalSize += rBox.getWidth() * rBox.getHeight();
965 Eigen::MatrixXd eigenTemplate(totalSize, 1);
966 Eigen::MatrixXd eigenScience(totalSize, 1);
967 Eigen::MatrixXd eigeniVariance(totalSize, 1);
968 eigenTemplate.setZero();
969 eigenScience.setZero();
970 eigeniVariance.setZero();
976 typename std::vector<afwGeom::Box2I>::iterator biter = boxArray.begin();
977 for (; biter != boxArray.end(); ++biter) {
978 int area = (*biter).getWidth() * (*biter).getHeight();
980 afwImage::Image<InputT> siTemplate(templateImage, *biter);
981 afwImage::Image<InputT> siScience(scienceImage, *biter);
982 afwImage::Image<InputT> sVarEstimate(varianceEstimate, *biter);
986 Eigen::MatrixXd eiVarEstimate =
imageToEigenMatrix(sVarEstimate).array().inverse().matrix();
988 eTemplate.resize(area, 1);
989 eScience.resize(area, 1);
990 eiVarEstimate.resize(area, 1);
992 eigenTemplate.block(nTerms, 0, area, 1) = eTemplate.block(0, 0, area, 1);
993 eigenScience.block(nTerms, 0, area, 1) = eScience.block(0, 0, area, 1);
994 eigeniVariance.block(nTerms, 0, area, 1) = eiVarEstimate.block(0, 0, area, 1);
999 afwImage::Image<InputT> cimage(templateImage.getDimensions());
1001 std::vector<Eigen::MatrixXd> convolvedEigenList(nKernelParameters);
1002 typename std::vector<Eigen::MatrixXd>::iterator eiter = convolvedEigenList.begin();
1004 for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
1005 afwMath::convolve(cimage, templateImage, **kiter,
false);
1006 Eigen::MatrixXd cMat(totalSize, 1);
1010 typename std::vector<afwGeom::Box2I>::iterator biter = boxArray.begin();
1011 for (; biter != boxArray.end(); ++biter) {
1012 int area = (*biter).getWidth() * (*biter).getHeight();
1014 afwImage::Image<InputT> csubimage(cimage, *biter);
1016 esubimage.resize(area, 1);
1017 cMat.block(nTerms, 0, area, 1) = esubimage.block(0, 0, area, 1);
1026 double time = t.elapsed();
1027 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
1028 "Total compute time to do basis convolutions : %.2f s", time);
1035 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
1036 typename std::vector<Eigen::MatrixXd>::iterator eiterj = convolvedEigenList.begin();
1037 typename std::vector<Eigen::MatrixXd>::iterator eiterE = convolvedEigenList.end();
1038 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
1039 cMat.col(kidxj) = eiterj->col(0);
1043 cMat.col(nParameters-1).fill(1.);
1046 this->
_ivVec = eigeniVariance.col(0);
1047 this->
_iVec = eigenScience.col(0);
1056 template <
typename InputT>
1058 lsst::afw::math::KernelList
const& basisList,
1059 bool fitForBackground,
1060 Eigen::MatrixXd
const& hMat,
1061 lsst::pex::policy::Policy policy
1069 template <
typename InputT>
1071 Eigen::MatrixXd vMat = this->
_cMat.jacobiSvd().matrixV();
1072 Eigen::MatrixXd vMatvMatT = vMat * vMat.transpose();
1075 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(this->
_mMat);
1076 Eigen::MatrixXd
const& rMat = eVecValues.eigenvectors();
1077 Eigen::VectorXd eValues = eVecValues.eigenvalues();
1078 double eMax = eValues.maxCoeff();
1079 for (
int i = 0; i != eValues.rows(); ++i) {
1080 if (eValues(i) == 0.0) {
1083 else if ((eMax / eValues(i)) > maxCond) {
1084 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1085 "Truncating eValue %d; %.5e / %.5e = %.5e vs. %.5e",
1086 i, eMax, eValues(i), eMax / eValues(i), maxCond);
1090 eValues(i) = 1.0 / eValues(i);
1093 Eigen::MatrixXd mInv = rMat * eValues.asDiagonal() * rMat.transpose();
1096 std::vector<double> risks;
1097 for (
unsigned int i = 0; i < lambdas.size(); i++) {
1098 double l = lambdas[i];
1099 Eigen::MatrixXd mLambda = this->
_mMat + l *
_hMat;
1103 }
catch (pexExcept::Exception &e) {
1104 LSST_EXCEPT_ADD(e,
"Unable to solve regularized kernel matrix");
1107 Eigen::VectorXd term1 = (this->
_aVec.transpose() * vMatvMatT * this->
_aVec);
1108 if (term1.size() != 1)
1109 throw LSST_EXCEPT(pexExcept::Exception,
"Matrix size mismatch");
1111 double term2a = (vMatvMatT * mLambda.inverse()).trace();
1113 Eigen::VectorXd term2b = (this->
_aVec.transpose() * (mInv * this->
_bVec));
1114 if (term2b.size() != 1)
1115 throw LSST_EXCEPT(pexExcept::Exception,
"Matrix size mismatch");
1117 double risk = term1(0) + 2 * (term2a - term2b(0));
1118 LOGL_DEBUG(
"TRACE4.ip.diffim.RegularizedKernelSolution.estimateRisk",
1119 "Lambda = %.3f, Risk = %.5e",
1121 LOGL_DEBUG(
"TRACE5.ip.diffim.RegularizedKernelSolution.estimateRisk",
1122 "%.5e + 2 * (%.5e - %.5e)",
1123 term1(0), term2a, term2b(0));
1124 risks.push_back(risk);
1126 std::vector<double>::iterator it = min_element(risks.begin(), risks.end());
1127 int index = distance(risks.begin(), it);
1128 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1129 "Minimum Risk = %.3e at lambda = %.3e", risks[index], lambdas[index]);
1131 return lambdas[index];
1135 template <
typename InputT>
1137 if (includeHmat ==
true) {
1145 template <
typename InputT>
1148 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1149 "cMat is %d x %d; vVec is %d; iVec is %d; hMat is %d x %d",
1154 std::cout <<
"ID: " << (this->
_id) << std::endl;
1155 std::cout <<
"C:" << std::endl;
1156 std::cout << this->
_cMat << std::endl;
1157 std::cout <<
"Sigma^{-1}:" << std::endl;
1158 std::cout << Eigen::MatrixXd(this->
_ivVec.asDiagonal()) << std::endl;
1159 std::cout <<
"Y:" << std::endl;
1160 std::cout << this->
_iVec << std::endl;
1161 std::cout <<
"H:" << std::endl;
1162 std::cout <<
_hMat << std::endl;
1219 std::string lambdaType =
_policy.getString(
"lambdaType");
1220 if (lambdaType ==
"absolute") {
1223 else if (lambdaType ==
"relative") {
1227 else if (lambdaType ==
"minimizeBiasedRisk") {
1228 double tol =
_policy.getDouble(
"maxConditionNumber");
1231 else if (lambdaType ==
"minimizeUnbiasedRisk") {
1235 throw LSST_EXCEPT(pexExcept::Exception,
"lambdaType in Policy not recognized");
1238 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1239 "Applying kernel regularization with lambda = %.2e",
_lambda);
1244 }
catch (pexExcept::Exception &e) {
1245 LSST_EXCEPT_ADD(e,
"Unable to solve static kernel matrix");
1252 template <
typename InputT>
1254 std::vector<double> lambdas;
1256 std::string lambdaStepType =
_policy.getString(
"lambdaStepType");
1257 if (lambdaStepType ==
"linear") {
1258 double lambdaLinMin =
_policy.getDouble(
"lambdaLinMin");
1259 double lambdaLinMax =
_policy.getDouble(
"lambdaLinMax");
1260 double lambdaLinStep =
_policy.getDouble(
"lambdaLinStep");
1261 for (
double l = lambdaLinMin; l <= lambdaLinMax; l += lambdaLinStep) {
1262 lambdas.push_back(l);
1265 else if (lambdaStepType ==
"log") {
1266 double lambdaLogMin =
_policy.getDouble(
"lambdaLogMin");
1267 double lambdaLogMax =
_policy.getDouble(
"lambdaLogMax");
1268 double lambdaLogStep =
_policy.getDouble(
"lambdaLogStep");
1269 for (
double l = lambdaLogMin; l <= lambdaLogMax; l += lambdaLogStep) {
1270 lambdas.push_back(pow(10, l));
1274 throw LSST_EXCEPT(pexExcept::Exception,
"lambdaStepType in Policy not recognized");
1282 lsst::afw::math::KernelList
const& basisList,
1283 lsst::afw::math::Kernel::SpatialFunctionPtr spatialKernelFunction,
1284 lsst::afw::math::Kernel::SpatialFunctionPtr background,
1285 lsst::pex::policy::Policy policy
1288 _spatialKernelFunction(spatialKernelFunction),
1289 _constantFirstTerm(false),
1299 bool isAlardLupton =
_policy.getString(
"kernelBasisSet") ==
"alard-lupton";
1300 bool usePca =
_policy.getBool(
"usePcaForSpatialKernel");
1301 if (isAlardLupton || usePca) {
1316 Eigen::MatrixXd mMat(
_nt,
_nt);
1317 Eigen::VectorXd bVec(
_nt);
1324 _kernel = std::shared_ptr<afwMath::LinearCombinationKernel>(
1328 LOGL_DEBUG(
"TRACE3.ip.diffim.SpatialKernelSolution",
1329 "Initializing with size %d %d %d and constant first term = %s",
1336 Eigen::MatrixXd
const& qMat,
1337 Eigen::VectorXd
const& wVec) {
1339 LOGL_DEBUG(
"TRACE5.ip.diffim.SpatialKernelSolution.addConstraint",
1340 "Adding candidate at %f, %f", xCenter, yCenter);
1344 Eigen::VectorXd pK(
_nkt);
1346 for (
int idx = 0; idx <
_nkt; idx++) { paramsK[idx] = 0.0; }
1347 for (
int idx = 0; idx <
_nkt; idx++) {
1350 pK(idx) = (*_spatialKernelFunction)(xCenter, yCenter);
1353 Eigen::MatrixXd pKpKt = (pK * pK.transpose());
1356 Eigen::MatrixXd pBpBt;
1357 Eigen::MatrixXd pKpBt;
1359 pB = Eigen::VectorXd(
_nbt);
1362 std::vector<double> paramsB =
_background->getParameters();
1363 for (
int idx = 0; idx <
_nbt; idx++) { paramsB[idx] = 0.0; }
1364 for (
int idx = 0; idx <
_nbt; idx++) {
1367 pB(idx) = (*_background)(xCenter, yCenter);
1370 pBpBt = (pB * pB.transpose());
1373 pKpBt = (pK * pB.transpose());
1377 std::cout <<
"Spatial weights" << std::endl;
1378 std::cout <<
"pKpKt " << pKpKt << std::endl;
1380 std::cout <<
"pBpBt " << pBpBt << std::endl;
1381 std::cout <<
"pKpBt " << pKpBt << std::endl;
1386 std::cout <<
"Spatial matrix inputs" << std::endl;
1387 std::cout <<
"M " << qMat << std::endl;
1388 std::cout <<
"B " << wVec << std::endl;
1402 _mMat(0, 0) += qMat(0,0);
1403 for(
int m2 = 1; m2 <
_nbases; m2++) {
1404 _mMat.block(0, m2*_nkt-dm, 1, _nkt) += qMat(0,m2) * pK.transpose();
1406 _bVec(0) += wVec(0);
1409 _mMat.block(0, mb, 1, _nbt) += qMat(0,_nbases) * pB.transpose();
1414 for(
int m1 = m0; m1 <
_nbases; m1++) {
1416 _mMat.block(m1*_nkt-dm, m1*_nkt-dm, _nkt, _nkt) +=
1417 (pKpKt * qMat(m1,m1)).triangularView<Eigen::Upper>();
1420 for(
int m2 = m1+1; m2 <
_nbases; m2++) {
1421 _mMat.block(m1*_nkt-dm, m2*_nkt-dm, _nkt, _nkt) += qMat(m1,m2) * pKpKt;
1426 _mMat.block(m1*_nkt-dm, mb, _nkt, _nbt) += qMat(m1,_nbases) * pKpBt;
1430 _bVec.segment(m1*_nkt-dm, _nkt) += wVec(m1) * pK;
1435 _mMat.block(mb, mb, _nbt, _nbt) +=
1436 (pBpBt * qMat(_nbases,_nbases)).triangularView<Eigen::Upper>();
1437 _bVec.segment(mb, _nbt) += wVec(_nbases) * pB;
1441 std::cout <<
"Spatial matrix outputs" << std::endl;
1442 std::cout <<
"mMat " <<
_mMat << std::endl;
1443 std::cout <<
"bVec " <<
_bVec << std::endl;
1450 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return image");
1452 std::shared_ptr<afwImage::Image<afwMath::Kernel::Pixel>> image(
1453 new afwImage::Image<afwMath::Kernel::Pixel>(
_kernel->getDimensions())
1455 (void)
_kernel->computeImage(*image,
false, pos[0], pos[1]);
1461 for (
int i = 0; i <
_nt; i++) {
1462 for (
int j = i+1; j <
_nt; j++) {
1469 }
catch (pexExcept::Exception &e) {
1470 LSST_EXCEPT_ADD(e,
"Unable to solve spatial kernel matrix");
1477 std::pair<std::shared_ptr<afwMath::LinearCombinationKernel>,
1480 throw LSST_EXCEPT(pexExcept::Exception,
"Kernel not solved; cannot return solution");
1494 std::vector<double> kCoeffs(
_nbases);
1495 for (
int i = 0; i <
_nbases; i++) {
1496 if (std::isnan(
_aVec(i))) {
1498 pexExcept::Exception,
1500 "I. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % i % cNumber));
1502 kCoeffs[i] =
_aVec(i);
1504 lsst::afw::math::KernelList basisList =
1505 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(
_kernel)->getKernelList();
1507 new afwMath::LinearCombinationKernel(basisList, kCoeffs)
1513 std::vector<std::vector<double> > kCoeffs;
1515 for (
int i = 0, idx = 0; i <
_nbases; i++) {
1516 kCoeffs.push_back(std::vector<double>(
_nkt));
1520 if (std::isnan(
_aVec(idx))) {
1522 pexExcept::Exception,
1524 "II. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1526 kCoeffs[i][0] =
_aVec(idx++);
1529 for (
int j = 0; j <
_nkt; j++) {
1530 if (std::isnan(
_aVec(idx))) {
1532 pexExcept::Exception,
1534 "III. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1536 kCoeffs[i][j] =
_aVec(idx++);
1540 _kernel->setSpatialParameters(kCoeffs);
1544 std::shared_ptr<ImageT> image (
new ImageT(
_kernel->getDimensions()));
1550 for (
int i = 0; i <
_nbt; i++) {
1551 int idx =
_nt - _nbt + i;
1552 if (std::isnan(
_aVec(idx))) {
1553 throw LSST_EXCEPT(pexExcept::Exception,
1555 "Unable to determine spatial background solution %d (nan)") % (idx)));
1557 bgCoeffs[i] =
_aVec(idx);
void _setKernel()
Set kernel after solution.
Eigen::MatrixXd _cMat
K_i x R.
Eigen::MatrixXi maskToEigenMatrix(lsst::afw::image::Mask< lsst::afw::image::MaskPixel > const &mask)
virtual std::pair< std::shared_ptr< lsst::afw::math::Kernel >, double > getSolutionPair()
Eigen::VectorXd _bVec
Derived least squares B vector.
SpatialKernelSolution(lsst::afw::math::KernelList const &basisList, lsst::afw::math::Kernel::SpatialFunctionPtr spatialKernelFunction, lsst::afw::math::Kernel::SpatialFunctionPtr background, lsst::pex::policy::Policy policy)
virtual std::shared_ptr< lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > > makeKernelImage()
KernelSolvedBy _solvedBy
Type of algorithm used to make solution.
StaticKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground)
double _background
Derived differential background estimate.
Eigen::VectorXd _iVec
Vectorized I.
Eigen::VectorXd _ivVec
Inverse variance.
virtual double getBackground()
std::pair< std::shared_ptr< lsst::afw::math::LinearCombinationKernel >, lsst::afw::math::Kernel::SpatialFunctionPtr > getSolutionPair()
Declaration of classes to store the solution for convolution kernels.
RegularizedKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground, Eigen::MatrixXd const &hMat, lsst::pex::policy::Policy policy)
virtual void build(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate)
void _setKernel()
Set kernel after solution.
virtual std::shared_ptr< lsst::afw::math::Kernel > getKernel()
double _kSum
Derived kernel sum.
static int _SolutionId
Unique identifier for solution.
void _setKernelUncertainty()
Not implemented.
bool _fitForBackground
Background terms included in fit.
lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > ImageT
virtual double getConditionNumber(ConditionNumberType conditionType)
int _id
Unique ID for object.
Eigen::MatrixXd imageToEigenMatrix(lsst::afw::image::Image< PixelT > const &img)
Turns a 2-d Image into a 2-d Eigen Matrix.
virtual void buildOrig(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate, lsst::afw::image::Mask< lsst::afw::image::MaskPixel > pixelMask)
lsst::afw::math::Kernel::SpatialFunctionPtr _spatialKernelFunction
Spatial function for Kernel.
Eigen::MatrixXd const _hMat
Regularization weights.
std::shared_ptr< lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > > makeKernelImage(lsst::afw::geom::Point2D const &pos)
int _nbt
Number of background terms.
Eigen::MatrixXd _mMat
Derived least squares M matrix.
bool _constantFirstTerm
Is the first term constant.
lsst::pex::policy::Policy _policy
Policy to control processing.
double _kSum
Derived kernel sum.
MaskedKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground)
lsst::afw::math::Kernel::SpatialFunctionPtr _background
Spatial background model.
void addConstraint(float xCenter, float yCenter, Eigen::MatrixXd const &qMat, Eigen::VectorXd const &wVec)
int _nkt
Number of kernel terms.
std::shared_ptr< lsst::afw::math::LinearCombinationKernel > _kernel
Spatial convolution kernel.
int _nbases
Number of basis functions.
virtual void buildSingleMaskOrig(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate, lsst::afw::geom::Box2I maskBox)
virtual void buildWithMask(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate, lsst::afw::image::Mask< lsst::afw::image::MaskPixel > const &pixelMask)
Eigen::MatrixXd const & getM()
double estimateRisk(double maxCond)
Eigen::VectorXd _aVec
Derived least squares solution matrix.
double _lambda
Overall regularization strength.
std::shared_ptr< lsst::afw::math::Kernel > _kernel
Derived single-object convolution kernel.
lsst::pex::policy::Policy _policy
std::vector< double > _createLambdaSteps()
Image Subtraction helper functions.
int _nt
Total number of terms.