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)
87 _fitForBackground(true)
100 switch (conditionType) {
103 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(mMat);
104 Eigen::VectorXd eValues = eVecValues.eigenvalues();
105 double eMax = eValues.maxCoeff();
106 double eMin = eValues.minCoeff();
107 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.getConditionNumber",
108 "EIGENVALUE eMax / eMin = %.3e", eMax / eMin);
109 return (eMax / eMin);
114 Eigen::VectorXd sValues = mMat.jacobiSvd().singularValues();
115 double sMax = sValues.maxCoeff();
116 double sMin = sValues.minCoeff();
117 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.getConditionNumber",
118 "SVD eMax / eMin = %.3e", sMax / sMin);
119 return (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()) {
151 aVec = lu.solve(bVec);
153 LOGL_DEBUG(
"TRACE3.ip.diffim.KernelSolution.solve",
154 "Unable to determine kernel via LU");
159 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(mMat);
160 Eigen::MatrixXd
const& rMat = eVecValues.eigenvectors();
161 Eigen::VectorXd eValues = eVecValues.eigenvalues();
163 for (
int i = 0; i != eValues.rows(); ++i) {
164 if (eValues(i) != 0.0) {
165 eValues(i) = 1.0/eValues(i);
169 aVec = rMat * eValues.asDiagonal() * rMat.transpose() * bVec;
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();
280 unsigned int const nKernelParameters = basisList.
size();
281 unsigned int const nBackgroundParameters = _fitForBackground ? 1 : 0;
282 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
319 unsigned int const startCol = goodBBox.
getMinX();
320 unsigned int const startRow = goodBBox.
getMinY();
322 unsigned int endCol = goodBBox.
getMaxX() + 1;
323 unsigned int endRow = goodBBox.
getMaxY() + 1;
338 startRow, startCol, endRow-startRow, endCol-startCol
339 ).array().inverse().matrix();
342 eigenTemplate.resize(eigenTemplate.rows()*eigenTemplate.cols(), 1);
343 eigenScience.resize(eigenScience.rows()*eigenScience.cols(), 1);
344 eigeniVariance.resize(eigeniVariance.rows()*eigeniVariance.cols(), 1);
357 for (kiter = basisList.
begin(); kiter != basisList.
end(); ++kiter, ++eiter) {
364 cMat.resize(cMat.size(), 1);
369 double time = t.elapsed();
370 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
371 "Total compute time to do basis convolutions : %.2f s", time);
378 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
381 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
382 cMat.col(kidxj) = eiterj->col(0);
385 if (_fitForBackground)
386 cMat.col(nParameters-1).fill(1.);
389 _ivVec = eigeniVariance.col(0);
390 _iVec = eigenScience.col(0);
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>
429 unsigned int const nParameters = _aVec.size();
430 unsigned int const nBackgroundParameters = _fitForBackground ? 1 : 0;
431 unsigned int const nKernelParameters =
432 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList().size();
433 if (nParameters != (nKernelParameters + nBackgroundParameters))
438 for (
unsigned int idx = 0; idx < nKernelParameters; idx++) {
441 str(boost::format(
"Unable to determine kernel solution %d (nan)") % idx));
443 kValues[idx] = _aVec(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)") %
458 _background = _aVec(nParameters-1);
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
549 afwDet::setMaskFromFootprint(finalMask,
556 for (
auto const & foot : *(maskedFpSetGrown.
getFootprints())) {
563 ndarray::Array<int, 1, 1> maskArray =
564 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
565 fullFp->getSpans()->flatten(maskArray, finalMask.
getArray(), templateImage.
getXY0());
566 auto maskEigen = ndarray::asEigenMatrix(maskArray);
568 ndarray::Array<InputT, 1, 1> arrayTemplate =
569 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
570 fullFp->getSpans()->flatten(arrayTemplate, templateImage.
getArray(), templateImage.
getXY0());
571 auto eigenTemplate0 = ndarray::asEigenMatrix(arrayTemplate);
573 ndarray::Array<InputT, 1, 1> arrayScience =
574 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
575 fullFp->getSpans()->flatten(arrayScience, scienceImage.
getArray(), scienceImage.
getXY0());
576 auto eigenScience0 = ndarray::asEigenMatrix(arrayScience);
578 ndarray::Array<afwImage::VariancePixel, 1, 1> arrayVariance =
579 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
580 fullFp->getSpans()->flatten(arrayVariance, varianceEstimate.
getArray(), varianceEstimate.
getXY0());
581 auto eigenVariance0 = ndarray::asEigenMatrix(arrayVariance);
584 for (
int i = 0; i < maskEigen.size(); i++) {
585 if (maskEigen(i) == 0.0)
589 Eigen::VectorXd eigenTemplate(nGood);
590 Eigen::VectorXd eigenScience(nGood);
591 Eigen::VectorXd eigenVariance(nGood);
593 for (
int i = 0; i < maskEigen.size(); i++) {
594 if (maskEigen(i) == 0.0) {
595 eigenTemplate(nUsed) = eigenTemplate0(i);
596 eigenScience(nUsed) = eigenScience0(i);
597 eigenVariance(nUsed) = eigenVariance0(i);
606 unsigned int const nKernelParameters = basisList.
size();
607 unsigned int const nBackgroundParameters = this->_fitForBackground ? 1 : 0;
608 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
622 for (kiter = basisList.
begin(); kiter != basisList.
end(); ++kiter, ++eiter) {
625 ndarray::Array<InputT, 1, 1> arrayC =
626 ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
627 fullFp->getSpans()->flatten(arrayC, cimage.
getArray(), cimage.
getXY0());
628 auto eigenC0 = ndarray::asEigenMatrix(arrayC);
630 Eigen::VectorXd eigenC(nGood);
632 for (
int i = 0; i < maskEigen.size(); i++) {
633 if (maskEigen(i) == 0.0) {
634 eigenC(nUsed) = eigenC0(i);
641 double time = t.elapsed();
642 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.buildWithMask",
643 "Total compute time to do basis convolutions : %.2f s", time);
647 Eigen::MatrixXd cMat(eigenTemplate.size(), nParameters);
650 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
651 cMat.block(0, kidxj, eigenTemplate.size(), 1) =
652 Eigen::MatrixXd(*eiterj).block(0, 0, eigenTemplate.size(), 1);
655 if (this->_fitForBackground)
656 cMat.col(nParameters-1).fill(1.);
659 this->_ivVec = eigenVariance.array().inverse().matrix();
660 this->_iVec = eigenScience;
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();
699 unsigned int const nKernelParameters = basisList.
size();
700 unsigned int const nBackgroundParameters = this->_fitForBackground ? 1 : 0;
701 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
708 geom::Box2I shrunkLocalBBox = (*kiter)->shrinkBBox(templateImage.
getBBox(afwImage::LOCAL));
709 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
710 "Limits of good pixels after convolution: %d,%d -> %d,%d (local)",
715 unsigned int startCol = shrunkLocalBBox.
getMinX();
716 unsigned int startRow = shrunkLocalBBox.
getMinY();
717 unsigned int endCol = shrunkLocalBBox.
getMaxX();
718 unsigned int endRow = shrunkLocalBBox.
getMaxY();
741 startRow, startCol, endRow-startRow, endCol-startCol
742 ).array().inverse().matrix();
745 eMask.resize(eMask.rows()*eMask.cols(), 1);
746 eigenTemplate.resize(eigenTemplate.rows()*eigenTemplate.cols(), 1);
747 eigenScience.resize(eigenScience.rows()*eigenScience.cols(), 1);
748 eigeniVariance.resize(eigeniVariance.rows()*eigeniVariance.cols(), 1);
751 Eigen::MatrixXd maskedEigenTemplate(eigenTemplate.rows(), 1);
752 Eigen::MatrixXd maskedEigenScience(eigenScience.rows(), 1);
753 Eigen::MatrixXd maskedEigeniVariance(eigeniVariance.rows(), 1);
755 for (
int i = 0; i < eMask.rows(); i++) {
756 if (eMask(i, 0) == 0) {
757 maskedEigenTemplate(nGood, 0) = eigenTemplate(i, 0);
758 maskedEigenScience(nGood, 0) = eigenScience(i, 0);
759 maskedEigeniVariance(nGood, 0) = eigeniVariance(i, 0);
764 eigenTemplate = maskedEigenTemplate.block(0, 0, nGood, 1);
765 eigenScience = maskedEigenScience.block(0, 0, nGood, 1);
766 eigeniVariance = maskedEigeniVariance.block(0, 0, nGood, 1);
780 for (kiter = basisList.
begin(); kiter != basisList.
end(); ++kiter, ++eiter) {
787 cMat.resize(cMat.size(), 1);
790 Eigen::MatrixXd maskedcMat(cMat.rows(), 1);
792 for (
int i = 0; i < eMask.rows(); i++) {
793 if (eMask(i, 0) == 0) {
794 maskedcMat(nGood, 0) = cMat(i, 0);
798 cMat = maskedcMat.block(0, 0, nGood, 1);
802 double time = t.elapsed();
803 LOGL_DEBUG(
"TRACE3.ip.diffim.StaticKernelSolution.build",
804 "Total compute time to do basis convolutions : %.2f s", time);
811 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
814 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
815 cMat.col(kidxj) = eiterj->col(0);
818 if (this->_fitForBackground)
819 cMat.col(nParameters-1).fill(1.);
822 this->_ivVec = eigeniVariance.col(0);
823 this->_iVec = eigenScience.col(0);
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();
854 unsigned int const nKernelParameters = basisList.
size();
855 unsigned int const nBackgroundParameters = this->_fitForBackground ? 1 : 0;
856 unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
886 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
887 "Limits of good pixels after convolution: %d,%d -> %d,%d",
891 unsigned int const startCol = shrunkBBox.
getMinX();
892 unsigned int const startRow = shrunkBBox.
getMinY();
893 unsigned int const endCol = shrunkBBox.
getMaxX();
894 unsigned int const endRow = shrunkBBox.
getMaxY();
909 int maskStartCol = maskBox.
getMinX();
910 int maskStartRow = maskBox.
getMinY();
911 int maskEndCol = maskBox.
getMaxX();
912 int maskEndRow = maskBox.
getMaxY();
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",
969 Eigen::MatrixXd eigenTemplate(totalSize, 1);
970 Eigen::MatrixXd eigenScience(totalSize, 1);
971 Eigen::MatrixXd eigeniVariance(totalSize, 1);
972 eigenTemplate.setZero();
973 eigenScience.setZero();
974 eigeniVariance.setZero();
981 for (; biter != boxArray.
end(); ++biter) {
982 int area = (*biter).getWidth() * (*biter).getHeight();
990 Eigen::MatrixXd eiVarEstimate =
imageToEigenMatrix(sVarEstimate).array().inverse().matrix();
992 eTemplate.resize(area, 1);
993 eScience.resize(area, 1);
994 eiVarEstimate.resize(area, 1);
996 eigenTemplate.block(nTerms, 0, area, 1) = eTemplate.block(0, 0, area, 1);
997 eigenScience.block(nTerms, 0, area, 1) = eScience.block(0, 0, area, 1);
998 eigeniVariance.block(nTerms, 0, area, 1) = eiVarEstimate.block(0, 0, area, 1);
1010 for (kiter = basisList.
begin(); kiter != basisList.
end(); ++kiter, ++eiter) {
1012 Eigen::MatrixXd cMat(totalSize, 1);
1017 for (; biter != boxArray.
end(); ++biter) {
1018 int area = (*biter).getWidth() * (*biter).getHeight();
1022 esubimage.resize(area, 1);
1023 cMat.block(nTerms, 0, area, 1) = esubimage.block(0, 0, area, 1);
1032 double time = t.elapsed();
1033 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
1034 "Total compute time to do basis convolutions : %.2f s", time);
1041 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
1044 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
1045 cMat.col(kidxj) = eiterj->col(0);
1048 if (this->_fitForBackground)
1049 cMat.col(nParameters-1).fill(1.);
1052 this->_ivVec = eigeniVariance.col(0);
1053 this->_iVec = eigenScience.col(0);
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();
1078 Eigen::MatrixXd vMatvMatT = vMat * vMat.transpose();
1081 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(this->_mMat);
1082 Eigen::MatrixXd
const& rMat = eVecValues.eigenvectors();
1083 Eigen::VectorXd eValues = eVecValues.eigenvalues();
1084 double eMax = eValues.maxCoeff();
1085 for (
int i = 0; i != eValues.rows(); ++i) {
1086 if (eValues(i) == 0.0) {
1089 else if ((eMax / eValues(i)) > maxCond) {
1090 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1091 "Truncating eValue %d; %.5e / %.5e = %.5e vs. %.5e",
1092 i, eMax, eValues(i), eMax / eValues(i), maxCond);
1096 eValues(i) = 1.0 / eValues(i);
1099 Eigen::MatrixXd mInv = rMat * eValues.asDiagonal() * rMat.transpose();
1103 for (
unsigned int i = 0; i < lambdas.
size(); i++) {
1104 double l = lambdas[i];
1105 Eigen::MatrixXd mLambda = this->_mMat + l * _hMat;
1113 Eigen::VectorXd term1 = (this->_aVec.transpose() * vMatvMatT * this->_aVec);
1114 if (term1.size() != 1)
1117 double term2a = (vMatvMatT * mLambda.inverse()).trace();
1119 Eigen::VectorXd term2b = (this->_aVec.transpose() * (mInv * this->_bVec));
1120 if (term2b.size() != 1)
1123 double risk = term1(0) + 2 * (term2a - term2b(0));
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)",
1129 term1(0), term2a, term2b(0));
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]);
1137 return lambdas[index];
1141 template <
typename InputT>
1143 if (includeHmat ==
true) {
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");
1266 double lambdaLinStep = _ps->getAsDouble(
"lambdaLinStep");
1267 for (
double l = lambdaLinMin; l <= lambdaLinMax; l += lambdaLinStep) {
1271 else if (lambdaStepType ==
"log") {
1272 double lambdaLogMin = _ps->getAsDouble(
"lambdaLogMin");
1273 double lambdaLogMax = _ps->getAsDouble(
"lambdaLogMax");
1274 double lambdaLogStep = _ps->getAsDouble(
"lambdaLogStep");
1275 for (
double l = lambdaLogMin; l <= lambdaLogMax; l += lambdaLogStep) {
1294 _spatialKernelFunction(spatialKernelFunction),
1295 _constantFirstTerm(false),
1297 _background(background),
1305 bool isAlardLupton = _ps->getAsString(
"kernelBasisSet") ==
"alard-lupton";
1306 bool usePca = _ps->getAsBool(
"usePcaForSpatialKernel");
1307 if (isAlardLupton || usePca) {
1308 _constantFirstTerm =
true;
1312 _nbases = basisList.
size();
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",
1346 "Adding candidate at %f, %f", xCenter, yCenter);
1350 Eigen::VectorXd pK(_nkt);
1352 for (
int idx = 0; idx < _nkt; idx++) { paramsK[idx] = 0.0; }
1353 for (
int idx = 0; idx < _nkt; idx++) {
1356 pK(idx) = (*_spatialKernelFunction)(xCenter, yCenter);
1359 Eigen::MatrixXd pKpKt = (pK * pK.transpose());
1362 Eigen::MatrixXd pBpBt;
1363 Eigen::MatrixXd pKpBt;
1365 pB = Eigen::VectorXd(_nbt);
1369 for (
int idx = 0; idx < _nbt; idx++) { paramsB[idx] = 0.0; }
1370 for (
int idx = 0; idx < _nbt; idx++) {
1373 pB(idx) = (*_background)(xCenter, yCenter);
1376 pBpBt = (pB * pB.transpose());
1379 pKpBt = (pK * pB.transpose());
1402 int mb = _nt - _nbt;
1404 if (_constantFirstTerm) {
1408 _mMat(0, 0) += qMat(0,0);
1409 for(
int m2 = 1; m2 < _nbases; m2++) {
1410 _mMat.block(0, m2*_nkt-dm, 1, _nkt) += qMat(0,m2) * pK.transpose();
1412 _bVec(0) += wVec(0);
1415 _mMat.block(0, mb, 1, _nbt) += qMat(0,_nbases) * pB.transpose();
1420 for(
int m1 = m0; m1 < _nbases; m1++) {
1422 _mMat.block(m1*_nkt-dm, m1*_nkt-dm, _nkt, _nkt) +=
1423 (pKpKt * qMat(m1,m1)).triangularView<Eigen::Upper>();
1426 for(
int m2 = m1+1; m2 < _nbases; m2++) {
1427 _mMat.block(m1*_nkt-dm, m2*_nkt-dm, _nkt, _nkt) += qMat(m1,m2) * pKpKt;
1432 _mMat.block(m1*_nkt-dm, mb, _nkt, _nbt) += qMat(m1,_nbases) * pKpBt;
1436 _bVec.segment(m1*_nkt-dm, _nkt) += wVec(m1) * pK;
1441 _mMat.block(mb, mb, _nbt, _nbt) +=
1442 (pBpBt * qMat(_nbases,_nbases)).triangularView<Eigen::Upper>();
1443 _bVec.segment(mb, _nbt) += wVec(_nbases) * pB;
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 LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Image Subtraction helper functions.
Declaration of classes to store the solution for convolution kernels.
LSST DM logging module built on log4cxx.
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
A Threshold is used to pass a threshold value to detection algorithms.
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
lsst::geom::Extent2I getDimensions() const
Return the image's size; useful for passing to constructors.
lsst::geom::Point2I getXY0() const
Return the image's origin.
A class to represent a 2-dimensional array of pixels.
Represent a 2-dimensional array of bitmask pixels.
void writeFits(std::string const &fileName, daf::base::PropertySet const *metadata=nullptr, std::string const &mode="w") const
Write a mask to a regular FITS file.
Parameters to control convolution.
void setDoNormalize(bool doNormalize)
void setParameters(std::vector< double > const ¶ms)
Set all function parameters.
std::vector< double > const & getParameters() const noexcept
Return all function parameters.
lsst::geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
void setSpatialParameters(const std::vector< std::vector< double > > params)
Set the parameters of all spatial functions.
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.
A kernel that is a linear combination of fixed basis kernels.
A class to evaluate image statistics.
double getValue(Property const prop=NOTHING) const
Return the value of the desired property (if specified in the constructor)
Class for storing generic metadata.
An integer coordinate rectangle.
int getMinY() const noexcept
int getHeight() const noexcept
int getMinX() const noexcept
int getWidth() const noexcept
int getMaxX() const noexcept
int getMaxY() const noexcept
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)
Provides consistent interface for LSST exceptions.
Reports invalid arguments.
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image.
@ MIN
estimate sample minimum
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)