17#include "boost/timer/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());
143 boost::timer::cpu_timer t;
145 LOGL_DEBUG(
"TRACE2.ip.diffim.KernelSolution.solve",
146 "Solving for kernel");
148 Eigen::FullPivLU<Eigen::MatrixXd>
lu(
mMat);
149 if (
lu.isInvertible()) {
152 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
153 "Unable to determine kernel via LU");
172 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
173 "Unable to determine kernel via eigen-values");
180 double time = 1
e-9 * t.elapsed().wall;
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();
325 boost::timer::cpu_timer t;
338 ).array().inverse().matrix();
369 double time = 1
e-9 * t.elapsed().wall;
370 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
371 "Total compute time to do basis convolutions : %.2f s", time);
384 if (_fitForBackground)
392 _mMat = _cMat.transpose() * (_ivVec.asDiagonal() * _cMat);
393 _bVec = _cMat.transpose() * (_ivVec.asDiagonal() * _iVec);
396 template <
typename InputT>
398 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.solve",
399 "mMat is %d x %d; bVec is %d; cMat is %d x %d; vVec is %d; iVec is %d",
400 _mMat.rows(), _mMat.cols(), _bVec.size(),
401 _cMat.rows(), _cMat.cols(), _ivVec.size(), _iVec.size());
422 template <
typename InputT>
431 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList().size();
440 str(boost::format(
"Unable to determine kernel solution %d (nan)") %
idx));
444 _kernel->setKernelParameters(
kValues);
447 new ImageT(_kernel->getDimensions())
449 _kSum = _kernel->computeImage(*image,
false);
451 if (_fitForBackground) {
454 str(boost::format(
"Unable to determine background solution %d (nan)") %
462 template <
typename InputT>
492 template <
typename InputT>
495 bool fitForBackground
500 template <
typename InputT>
511 "Error: variance less than 0.0");
515 "Error: variance equals 0.0, cannot inverse variance weight");
523 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
538 int growPix = (*kiter)->getCtr().getX();
542 for (
typename afwDet::FootprintSet::FootprintList::iterator
563 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
568 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
573 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
577 ndarray::Array<afwImage::VariancePixel, 1, 1>
arrayVariance =
578 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
602 boost::timer::cpu_timer t;
623 ndarray::Array<InputT, 1, 1>
arrayC =
624 ndarray::allocate(ndarray::makeVector(
fullFp->getArea()));
640 double time = 1
e-9 * t.elapsed().wall;
641 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.buildWithMask",
642 "Total compute time to do basis convolutions : %.2f s", time);
650 Eigen::MatrixXd(*eiterj).block(0, 0,
eigenTemplate.size(), 1);
653 if (this->_fitForBackground)
661 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * (this->_cMat);
662 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * (this->_iVec);
666 template <
typename InputT>
677 "Error: variance less than 0.0");
681 "Error: variance equals 0.0, cannot inverse variance weight");
685 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
707 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
708 "Limits of good pixels after convolution: %d,%d -> %d,%d (local)",
721 boost::timer::cpu_timer t;
739 ).array().inverse().matrix();
752 for (
int i = 0;
i <
eMask.rows();
i++) {
789 for (
int i = 0;
i <
eMask.rows();
i++) {
800 double time = 1
e-9 * t.elapsed().wall;
801 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
802 "Total compute time to do basis convolutions : %.2f s", time);
815 if (this->_fitForBackground)
823 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
824 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
830 template <
typename InputT>
841 "Error: variance less than 0.0");
845 "Error: variance equals 0.0, cannot inverse variance weight");
849 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
883 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
884 "Limits of good pixels after convolution: %d,%d -> %d,%d",
942 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
943 "Upper good pixel region: %d,%d -> %d,%d",
945 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
946 "Bottom good pixel region: %d,%d -> %d,%d",
948 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
949 "Left good pixel region: %d,%d -> %d,%d",
951 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
952 "Right good pixel region: %d,%d -> %d,%d",
973 boost::timer::cpu_timer t;
976 typename std::vector<geom::Box2I>::iterator
biter =
boxArray.begin();
978 int area = (*biter).getWidth() * (*biter).getHeight();
1012 typename std::vector<geom::Box2I>::iterator
biter =
boxArray.begin();
1014 int area = (*biter).getWidth() * (*biter).getHeight();
1029 double time = 1
e-9 * t.elapsed().wall;
1030 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
1031 "Total compute time to do basis convolutions : %.2f s", time);
1044 if (this->_fitForBackground)
1052 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
1053 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
1058 template <
typename InputT>
1061 bool fitForBackground,
1062 Eigen::MatrixXd
const& hMat,
1071 template <
typename InputT>
1073 Eigen::MatrixXd
vMat = this->_cMat.jacobiSvd().matrixV();
1077 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd>
eVecValues(this->_mMat);
1086 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1087 "Truncating eValue %d; %.5e / %.5e = %.5e vs. %.5e",
1099 for (
unsigned int i = 0;
i <
lambdas.size();
i++) {
1101 Eigen::MatrixXd
mLambda = this->_mMat +
l * _hMat;
1109 Eigen::VectorXd
term1 = (this->_aVec.transpose() *
vMatvMatT * this->_aVec);
1110 if (
term1.size() != 1)
1115 Eigen::VectorXd
term2b = (this->_aVec.transpose() * (
mInv * this->_bVec));
1120 LOGL_DEBUG(
"TRACE4.ip.diffim.RegularizedKernelSolution.estimateRisk",
1121 "Lambda = %.3f, Risk = %.5e",
1123 LOGL_DEBUG(
"TRACE5.ip.diffim.RegularizedKernelSolution.estimateRisk",
1124 "%.5e + 2 * (%.5e - %.5e)",
1128 std::vector<double>::iterator
it = min_element(
risks.begin(),
risks.end());
1129 int index = distance(
risks.begin(),
it);
1130 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1131 "Minimum Risk = %.3e at lambda = %.3e",
risks[index],
lambdas[index]);
1137 template <
typename InputT>
1140 return this->_mMat + _lambda * _hMat;
1147 template <
typename InputT>
1150 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1151 "cMat is %d x %d; vVec is %d; iVec is %d; hMat is %d x %d",
1152 this->_cMat.rows(),
this->_cMat.cols(),
this->_ivVec.size(),
1153 this->_iVec.size(), _hMat.rows(), _hMat.cols());
1168 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
1169 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
1221 std::string lambdaType = _ps->getAsString(
"lambdaType");
1222 if (lambdaType ==
"absolute") {
1223 _lambda = _ps->getAsDouble(
"lambdaValue");
1225 else if (lambdaType ==
"relative") {
1226 _lambda = this->_mMat.trace() / this->_hMat.trace();
1227 _lambda *= _ps->getAsDouble(
"lambdaScaling");
1229 else if (lambdaType ==
"minimizeBiasedRisk") {
1230 double tol = _ps->getAsDouble(
"maxConditionNumber");
1231 _lambda = estimateRisk(
tol);
1233 else if (lambdaType ==
"minimizeUnbiasedRisk") {
1240 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1241 "Applying kernel regularization with lambda = %.2e", _lambda);
1254 template <
typename InputT>
1258 std::string lambdaStepType = _ps->getAsString(
"lambdaStepType");
1259 if (lambdaStepType ==
"linear") {
1260 double lambdaLinMin = _ps->getAsDouble(
"lambdaLinMin");
1261 double lambdaLinMax = _ps->getAsDouble(
"lambdaLinMax");
1267 else if (lambdaStepType ==
"log") {
1268 double lambdaLogMin = _ps->getAsDouble(
"lambdaLogMin");
1269 double lambdaLogMax = _ps->getAsDouble(
"lambdaLogMax");
1291 _constantFirstTerm(
false),
1293 _background(background),
1301 bool isAlardLupton = _ps->getAsString(
"kernelBasisSet") ==
"alard-lupton";
1302 bool usePca = _ps->getAsBool(
"usePcaForSpatialKernel");
1304 _constantFirstTerm =
true;
1312 if (_constantFirstTerm) {
1313 _nt = (_nbases - 1) * _nkt + 1 + _nbt;
1315 _nt = _nbases * _nkt + _nbt;
1318 Eigen::MatrixXd
mMat(_nt, _nt);
1319 Eigen::VectorXd
bVec(_nt);
1330 LOGL_DEBUG(
"TRACE3.ip.diffim.SpatialKernelSolution",
1331 "Initializing with size %d %d %d and constant first term = %s",
1333 _constantFirstTerm ?
"true" :
"false");
1338 Eigen::MatrixXd
const&
qMat,
1339 Eigen::VectorXd
const&
wVec) {
1341 LOGL_DEBUG(
"TRACE5.ip.diffim.SpatialKernelSolution.addConstraint",
1346 Eigen::VectorXd
pK(_nkt);
1355 Eigen::MatrixXd
pKpKt = (
pK *
pK.transpose());
1358 Eigen::MatrixXd
pBpBt;
1359 Eigen::MatrixXd
pKpBt;
1361 pB = Eigen::VectorXd(_nbt);
1398 int mb = _nt - _nbt;
1400 if (_constantFirstTerm) {
1405 for(
int m2 = 1;
m2 < _nbases;
m2++) {
1411 _mMat.block(0,
mb, 1, _nbt) +=
qMat(0,_nbases) *
pB.transpose();
1416 for(
int m1 =
m0;
m1 < _nbases;
m1++) {
1422 for(
int m2 =
m1+1;
m2 < _nbases;
m2++) {
1463 for (
int i = 0;
i < _nt;
i++) {
1464 for (
int j =
i+1;
j < _nt;
j++) {
1488 void SpatialKernelSolution::_setKernel() {
1497 for (
int i = 0;
i < _nbases;
i++) {
1502 "I. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") %
i %
cNumber));
1504 kCoeffs[i] =
_aVec(i);
1507 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList();
1517 for (
int i = 0, idx = 0; i < _nbases; i++) {
1521 if ((i == 0) && (_constantFirstTerm)) {
1526 "II. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1528 kCoeffs[i][0] =
_aVec(idx++);
1531 for (
int j = 0; j < _nkt; j++) {
1536 "III. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1538 kCoeffs[i][j] =
_aVec(idx++);
1552 for (
int i = 0; i < _nbt; i++) {
1553 int idx = _nt - _nbt + i;
1557 "Unable to determine spatial background solution %d (nan)") % (idx)));
1559 bgCoeffs[i] =
_aVec(idx);
#define LSST_EXCEPT_ADD(e, m)
#define LSST_EXCEPT(type,...)
Image Subtraction helper functions.
Declaration of classes to store the solution for convolution kernels.
#define LOGL_DEBUG(logger, message...)
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)