17#include "boost/timer.hpp"
20#include "Eigen/Cholesky"
23#include "Eigen/Eigenvalues"
38#include "ndarray/eigen.h"
41#define DEBUG_MATRIX2 0
67 _fitForBackground(fitForBackground)
78 _fitForBackground(fitForBackground)
107 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.getConditionNumber",
108 "EIGENVALUE eMax / eMin = %.3e",
eMax /
eMin);
117 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.getConditionNumber",
118 "SVD eMax / eMin = %.3e",
sMax /
sMin);
125 "Undefined ConditionNumberType : only EIGENVALUE, SVD allowed.");
132 Eigen::VectorXd
const&
bVec) {
141 Eigen::VectorXd
aVec = Eigen::VectorXd::Zero(
bVec.size());
146 LOGL_DEBUG(
"TRACE2.ip.diffim.KernelSolution.solve",
147 "Solving for kernel");
149 Eigen::FullPivLU<Eigen::MatrixXd>
lu(
mMat);
150 if (
lu.isInvertible()) {
153 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
154 "Unable to determine kernel via LU");
173 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
174 "Unable to determine kernel via eigen-values");
180 double time = t.elapsed();
181 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
182 "Compute time for matrix math : %.2f s", time);
194 template <
typename InputT>
197 bool fitForBackground
214 template <
typename InputT>
222 template <
typename InputT>
230 (
void)_kernel->computeImage(*image,
false);
234 template <
typename InputT>
242 template <
typename InputT>
250 template <
typename InputT>
260 template <
typename InputT>
270 "Error: variance less than 0.0");
274 "Error: variance equals 0.0, cannot inverse variance weight");
278 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList();
339 ).array().inverse().matrix();
369 double time = t.elapsed();
370 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
371 "Total compute time to do basis convolutions : %.2f s", time);
385 if (_fitForBackground)
393 _mMat = _cMat.transpose() * (_ivVec.asDiagonal() * _cMat);
394 _bVec = _cMat.transpose() * (_ivVec.asDiagonal() * _iVec);
397 template <
typename InputT>
399 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.solve",
400 "mMat is %d x %d; bVec is %d; cMat is %d x %d; vVec is %d; iVec is %d",
401 _mMat.rows(), _mMat.cols(), _bVec.size(),
402 _cMat.rows(), _cMat.cols(), _ivVec.size(), _iVec.size());
423 template <
typename InputT>
432 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList().size();
441 str(boost::format(
"Unable to determine kernel solution %d (nan)") %
idx));
445 _kernel->setKernelParameters(
kValues);
448 new ImageT(_kernel->getDimensions())
450 _kSum = _kernel->computeImage(*image,
false);
452 if (_fitForBackground) {
455 str(boost::format(
"Unable to determine background solution %d (nan)") %
463 template <
typename InputT>
493 template <
typename InputT>
496 bool fitForBackground
501 template <
typename InputT>
512 "Error: variance less than 0.0");
516 "Error: variance equals 0.0, cannot inverse variance weight");
524 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
539 int growPix = (*kiter)->getCtr().getX();
543 for (
typename afwDet::FootprintSet::FootprintList::iterator
564 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
569 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
574 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
578 ndarray::Array<afwImage::VariancePixel, 1, 1>
arrayVariance =
579 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
625 ndarray::Array<InputT, 1, 1>
arrayC =
626 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
641 double time = t.elapsed();
642 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.buildWithMask",
643 "Total compute time to do basis convolutions : %.2f s", time);
652 Eigen::MatrixXd(*eiterj).block(0, 0,
eigenTemplate.size(), 1);
655 if (this->_fitForBackground)
663 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * (this->_cMat);
664 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * (this->_iVec);
668 template <
typename InputT>
679 "Error: variance less than 0.0");
683 "Error: variance equals 0.0, cannot inverse variance weight");
687 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
709 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
710 "Limits of good pixels after convolution: %d,%d -> %d,%d (local)",
742 ).array().inverse().matrix();
755 for (
int i = 0;
i <
eMask.rows();
i++) {
792 for (
int i = 0;
i <
eMask.rows();
i++) {
802 double time = t.elapsed();
803 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
804 "Total compute time to do basis convolutions : %.2f s", time);
818 if (this->_fitForBackground)
826 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
827 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
833 template <
typename InputT>
844 "Error: variance less than 0.0");
848 "Error: variance equals 0.0, cannot inverse variance weight");
852 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
886 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
887 "Limits of good pixels after convolution: %d,%d -> %d,%d",
945 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
946 "Upper good pixel region: %d,%d -> %d,%d",
948 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
949 "Bottom good pixel region: %d,%d -> %d,%d",
951 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
952 "Left good pixel region: %d,%d -> %d,%d",
954 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
955 "Right good pixel region: %d,%d -> %d,%d",
980 typename std::vector<geom::Box2I>::iterator
biter =
boxArray.begin();
982 int area = (*biter).getWidth() * (*biter).getHeight();
1016 typename std::vector<geom::Box2I>::iterator
biter =
boxArray.begin();
1018 int area = (*biter).getWidth() * (*biter).getHeight();
1032 double time = t.elapsed();
1033 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
1034 "Total compute time to do basis convolutions : %.2f s", time);
1048 if (this->_fitForBackground)
1056 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
1057 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
1062 template <
typename InputT>
1065 bool fitForBackground,
1066 Eigen::MatrixXd
const& hMat,
1075 template <
typename InputT>
1077 Eigen::MatrixXd
vMat = this->_cMat.jacobiSvd().matrixV();
1081 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd>
eVecValues(this->_mMat);
1090 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1091 "Truncating eValue %d; %.5e / %.5e = %.5e vs. %.5e",
1103 for (
unsigned int i = 0;
i <
lambdas.size();
i++) {
1105 Eigen::MatrixXd
mLambda = this->_mMat +
l * _hMat;
1113 Eigen::VectorXd
term1 = (this->_aVec.transpose() *
vMatvMatT * this->_aVec);
1114 if (
term1.size() != 1)
1119 Eigen::VectorXd
term2b = (this->_aVec.transpose() * (
mInv * this->_bVec));
1124 LOGL_DEBUG(
"TRACE4.ip.diffim.RegularizedKernelSolution.estimateRisk",
1125 "Lambda = %.3f, Risk = %.5e",
1127 LOGL_DEBUG(
"TRACE5.ip.diffim.RegularizedKernelSolution.estimateRisk",
1128 "%.5e + 2 * (%.5e - %.5e)",
1132 std::vector<double>::iterator
it = min_element(
risks.begin(),
risks.end());
1133 int index = distance(
risks.begin(),
it);
1134 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1135 "Minimum Risk = %.3e at lambda = %.3e",
risks[index],
lambdas[index]);
1141 template <
typename InputT>
1144 return this->_mMat + _lambda * _hMat;
1151 template <
typename InputT>
1154 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1155 "cMat is %d x %d; vVec is %d; iVec is %d; hMat is %d x %d",
1156 this->_cMat.rows(),
this->_cMat.cols(),
this->_ivVec.size(),
1157 this->_iVec.size(), _hMat.rows(), _hMat.cols());
1172 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
1173 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
1225 std::string lambdaType = _ps->getAsString(
"lambdaType");
1226 if (lambdaType ==
"absolute") {
1227 _lambda = _ps->getAsDouble(
"lambdaValue");
1229 else if (lambdaType ==
"relative") {
1230 _lambda = this->_mMat.trace() / this->_hMat.trace();
1231 _lambda *= _ps->getAsDouble(
"lambdaScaling");
1233 else if (lambdaType ==
"minimizeBiasedRisk") {
1234 double tol = _ps->getAsDouble(
"maxConditionNumber");
1235 _lambda = estimateRisk(
tol);
1237 else if (lambdaType ==
"minimizeUnbiasedRisk") {
1244 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1245 "Applying kernel regularization with lambda = %.2e", _lambda);
1258 template <
typename InputT>
1262 std::string lambdaStepType = _ps->getAsString(
"lambdaStepType");
1263 if (lambdaStepType ==
"linear") {
1264 double lambdaLinMin = _ps->getAsDouble(
"lambdaLinMin");
1265 double lambdaLinMax = _ps->getAsDouble(
"lambdaLinMax");
1271 else if (lambdaStepType ==
"log") {
1272 double lambdaLogMin = _ps->getAsDouble(
"lambdaLogMin");
1273 double lambdaLogMax = _ps->getAsDouble(
"lambdaLogMax");
1295 _constantFirstTerm(
false),
1297 _background(background),
1305 bool isAlardLupton = _ps->getAsString(
"kernelBasisSet") ==
"alard-lupton";
1306 bool usePca = _ps->getAsBool(
"usePcaForSpatialKernel");
1308 _constantFirstTerm =
true;
1316 if (_constantFirstTerm) {
1317 _nt = (_nbases - 1) * _nkt + 1 + _nbt;
1319 _nt = _nbases * _nkt + _nbt;
1322 Eigen::MatrixXd
mMat(_nt, _nt);
1323 Eigen::VectorXd
bVec(_nt);
1334 LOGL_DEBUG(
"TRACE3.ip.diffim.SpatialKernelSolution",
1335 "Initializing with size %d %d %d and constant first term = %s",
1337 _constantFirstTerm ?
"true" :
"false");
1342 Eigen::MatrixXd
const&
qMat,
1343 Eigen::VectorXd
const&
wVec) {
1345 LOGL_DEBUG(
"TRACE5.ip.diffim.SpatialKernelSolution.addConstraint",
1350 Eigen::VectorXd
pK(_nkt);
1359 Eigen::MatrixXd
pKpKt = (
pK *
pK.transpose());
1362 Eigen::MatrixXd
pBpBt;
1363 Eigen::MatrixXd
pKpBt;
1365 pB = Eigen::VectorXd(_nbt);
1402 int mb = _nt - _nbt;
1404 if (_constantFirstTerm) {
1409 for(
int m2 = 1;
m2 < _nbases;
m2++) {
1415 _mMat.block(0,
mb, 1, _nbt) +=
qMat(0,_nbases) *
pB.transpose();
1420 for(
int m1 =
m0;
m1 < _nbases;
m1++) {
1426 for(
int m2 =
m1+1;
m2 < _nbases;
m2++) {
1467 for (
int i = 0;
i < _nt;
i++) {
1468 for (
int j =
i+1;
j < _nt;
j++) {
1492 void SpatialKernelSolution::_setKernel() {
1501 for (
int i = 0;
i < _nbases;
i++) {
1506 "I. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") %
i %
cNumber));
1508 kCoeffs[i] =
_aVec(i);
1511 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList();
1521 for (
int i = 0, idx = 0; i < _nbases; i++) {
1525 if ((i == 0) && (_constantFirstTerm)) {
1530 "II. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1532 kCoeffs[i][0] =
_aVec(idx++);
1535 for (
int j = 0; j < _nkt; j++) {
1540 "III. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1542 kCoeffs[i][j] =
_aVec(idx++);
1556 for (
int i = 0; i < _nbt; i++) {
1557 int idx = _nt - _nbt + i;
1561 "Unable to determine spatial background solution %d (nan)") % (idx)));
1563 bgCoeffs[i] =
_aVec(idx);
#define LOGL_DEBUG(logger, message...)
#define LSST_EXCEPT_ADD(e, m)
#define LSST_EXCEPT(type,...)
Image Subtraction helper functions.
Declaration of classes to store the solution for convolution kernels.
void setDoNormalize(bool doNormalize)
void setParameters(std::vector< double > const ¶ms)
std::vector< double > const & getParameters() const noexcept
lsst::geom::Extent2I const getDimensions() const
void setSpatialParameters(const std::vector< std::vector< double > > params)
double computeImage(lsst::afw::image::Image< Pixel > &image, bool doNormalize, double x=0.0, double y=0.0) const
bool _fitForBackground
Background terms included in fit.
virtual double getConditionNumber(ConditionNumberType conditionType)
Eigen::VectorXd _bVec
Derived least squares B vector.
Eigen::MatrixXd const & getM()
Eigen::VectorXd _aVec
Derived least squares solution matrix.
KernelSolvedBy _solvedBy
Type of algorithm used to make solution.
Eigen::MatrixXd _mMat
Derived least squares M matrix.
static int _SolutionId
Unique identifier for solution.
lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > ImageT
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)
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::geom::Box2I maskBox)
MaskedKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground)
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)
RegularizedKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground, Eigen::MatrixXd const &hMat, lsst::daf::base::PropertySet const &ps)
double estimateRisk(double maxCond)
std::pair< std::shared_ptr< lsst::afw::math::LinearCombinationKernel >, lsst::afw::math::Kernel::SpatialFunctionPtr > getSolutionPair()
std::shared_ptr< lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > > makeKernelImage(lsst::geom::Point2D const &pos)
SpatialKernelSolution(lsst::afw::math::KernelList const &basisList, lsst::afw::math::Kernel::SpatialFunctionPtr spatialKernelFunction, lsst::afw::math::Kernel::SpatialFunctionPtr background, lsst::daf::base::PropertySet const &ps)
void addConstraint(float xCenter, float yCenter, Eigen::MatrixXd const &qMat, Eigen::VectorXd const &wVec)
virtual std::pair< std::shared_ptr< lsst::afw::math::Kernel >, double > getSolutionPair()
void _setKernel()
Set kernel after solution.
virtual double getBackground()
virtual std::shared_ptr< lsst::afw::math::Kernel > getKernel()
std::shared_ptr< lsst::afw::math::Kernel > _kernel
Derived single-object convolution kernel.
void _setKernelUncertainty()
Not implemented.
virtual std::shared_ptr< lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > > makeKernelImage()
StaticKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground)
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)
Asseses the quality of a candidate given a spatial kernel and background model.
AssessSpatialKernelVisitor(std::shared_ptr< lsst::afw::math::LinearCombinationKernel > spatialKernel, lsst::afw::math::Kernel::SpatialFunctionPtr spatialBackground, lsst::daf::base::PropertySet const &ps)
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Eigen::MatrixXd imageToEigenMatrix(lsst::afw::image::Image< PixelT > const &img)
Turns a 2-d Image into a 2-d Eigen Matrix.
Eigen::MatrixXi maskToEigenMatrix(lsst::afw::image::Mask< lsst::afw::image::MaskPixel > const &mask)