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();
913 int maskStartCol = maskBox.
getMinX();
914 int maskStartRow = maskBox.
getMinY();
915 int maskEndCol = maskBox.
getMaxX();
916 int maskEndRow = maskBox.
getMaxY();
949 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
950 "Upper good pixel region: %d,%d -> %d,%d",
952 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
953 "Bottom good pixel region: %d,%d -> %d,%d",
955 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
956 "Left good pixel region: %d,%d -> %d,%d",
958 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
959 "Right good pixel region: %d,%d -> %d,%d",
973 Eigen::MatrixXd eigenTemplate(totalSize, 1);
974 Eigen::MatrixXd eigenScience(totalSize, 1);
975 Eigen::MatrixXd eigeniVariance(totalSize, 1);
976 eigenTemplate.setZero();
977 eigenScience.setZero();
978 eigeniVariance.setZero();
985 for (; biter != boxArray.
end(); ++biter) {
986 int area = (*biter).getWidth() * (*biter).getHeight();
994 Eigen::MatrixXd eiVarEstimate =
imageToEigenMatrix(sVarEstimate).array().inverse().matrix();
996 eTemplate.resize(area, 1);
997 eScience.resize(area, 1);
998 eiVarEstimate.resize(area, 1);
1000 eigenTemplate.block(nTerms, 0, area, 1) = eTemplate.block(0, 0, area, 1);
1001 eigenScience.block(nTerms, 0, area, 1) = eScience.block(0, 0, area, 1);
1002 eigeniVariance.block(nTerms, 0, area, 1) = eiVarEstimate.block(0, 0, area, 1);
1014 for (kiter = basisList.
begin(); kiter != basisList.
end(); ++kiter, ++eiter) {
1016 Eigen::MatrixXd cMat(totalSize, 1);
1021 for (; biter != boxArray.
end(); ++biter) {
1022 int area = (*biter).getWidth() * (*biter).getHeight();
1026 esubimage.resize(area, 1);
1027 cMat.block(nTerms, 0, area, 1) = esubimage.block(0, 0, area, 1);
1036 double time = t.elapsed();
1037 LOGL_DEBUG(
"TRACE3.ip.diffim.MaskedKernelSolution.build",
1038 "Total compute time to do basis convolutions : %.2f s", time);
1045 Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
1048 for (
unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
1049 cMat.col(kidxj) = eiterj->col(0);
1052 if (this->_fitForBackground)
1053 cMat.col(nParameters-1).fill(1.);
1056 this->_ivVec = eigeniVariance.col(0);
1057 this->_iVec = eigenScience.col(0);
1060 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
1061 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
1066 template <
typename InputT>
1069 bool fitForBackground,
1070 Eigen::MatrixXd
const& hMat,
1079 template <
typename InputT>
1081 Eigen::MatrixXd vMat = this->_cMat.jacobiSvd().matrixV();
1082 Eigen::MatrixXd vMatvMatT = vMat * vMat.transpose();
1085 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(this->_mMat);
1086 Eigen::MatrixXd
const& rMat = eVecValues.eigenvectors();
1087 Eigen::VectorXd eValues = eVecValues.eigenvalues();
1088 double eMax = eValues.maxCoeff();
1089 for (
int i = 0; i != eValues.rows(); ++i) {
1090 if (eValues(i) == 0.0) {
1093 else if ((eMax / eValues(i)) > maxCond) {
1094 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1095 "Truncating eValue %d; %.5e / %.5e = %.5e vs. %.5e",
1096 i, eMax, eValues(i), eMax / eValues(i), maxCond);
1100 eValues(i) = 1.0 / eValues(i);
1103 Eigen::MatrixXd mInv = rMat * eValues.asDiagonal() * rMat.transpose();
1107 for (
unsigned int i = 0; i < lambdas.
size(); i++) {
1108 double l = lambdas[i];
1109 Eigen::MatrixXd mLambda = this->_mMat + l * _hMat;
1117 Eigen::VectorXd term1 = (this->_aVec.transpose() * vMatvMatT * this->_aVec);
1118 if (term1.size() != 1)
1121 double term2a = (vMatvMatT * mLambda.inverse()).trace();
1123 Eigen::VectorXd term2b = (this->_aVec.transpose() * (mInv * this->_bVec));
1124 if (term2b.size() != 1)
1127 double risk = term1(0) + 2 * (term2a - term2b(0));
1128 LOGL_DEBUG(
"TRACE4.ip.diffim.RegularizedKernelSolution.estimateRisk",
1129 "Lambda = %.3f, Risk = %.5e",
1131 LOGL_DEBUG(
"TRACE5.ip.diffim.RegularizedKernelSolution.estimateRisk",
1132 "%.5e + 2 * (%.5e - %.5e)",
1133 term1(0), term2a, term2b(0));
1137 int index = distance(risks.
begin(), it);
1138 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1139 "Minimum Risk = %.3e at lambda = %.3e", risks[index], lambdas[index]);
1141 return lambdas[index];
1145 template <
typename InputT>
1147 if (includeHmat ==
true) {
1148 return this->_mMat + _lambda * _hMat;
1155 template <
typename InputT>
1158 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1159 "cMat is %d x %d; vVec is %d; iVec is %d; hMat is %d x %d",
1160 this->_cMat.rows(), this->_cMat.cols(), this->_ivVec.size(),
1161 this->_iVec.size(), _hMat.rows(), _hMat.cols());
1176 this->_mMat = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_cMat;
1177 this->_bVec = this->_cMat.transpose() * this->_ivVec.asDiagonal() * this->_iVec;
1229 std::string lambdaType = _ps->getAsString(
"lambdaType");
1230 if (lambdaType ==
"absolute") {
1231 _lambda = _ps->getAsDouble(
"lambdaValue");
1233 else if (lambdaType ==
"relative") {
1234 _lambda = this->_mMat.trace() / this->_hMat.trace();
1235 _lambda *= _ps->getAsDouble(
"lambdaScaling");
1237 else if (lambdaType ==
"minimizeBiasedRisk") {
1238 double tol = _ps->getAsDouble(
"maxConditionNumber");
1239 _lambda = estimateRisk(tol);
1241 else if (lambdaType ==
"minimizeUnbiasedRisk") {
1248 LOGL_DEBUG(
"TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1249 "Applying kernel regularization with lambda = %.2e", _lambda);
1262 template <
typename InputT>
1266 std::string lambdaStepType = _ps->getAsString(
"lambdaStepType");
1267 if (lambdaStepType ==
"linear") {
1268 double lambdaLinMin = _ps->getAsDouble(
"lambdaLinMin");
1269 double lambdaLinMax = _ps->getAsDouble(
"lambdaLinMax");
1270 double lambdaLinStep = _ps->getAsDouble(
"lambdaLinStep");
1271 for (
double l = lambdaLinMin; l <= lambdaLinMax; l += lambdaLinStep) {
1275 else if (lambdaStepType ==
"log") {
1276 double lambdaLogMin = _ps->getAsDouble(
"lambdaLogMin");
1277 double lambdaLogMax = _ps->getAsDouble(
"lambdaLogMax");
1278 double lambdaLogStep = _ps->getAsDouble(
"lambdaLogStep");
1279 for (
double l = lambdaLogMin; l <= lambdaLogMax; l += lambdaLogStep) {
1298 _spatialKernelFunction(spatialKernelFunction),
1299 _constantFirstTerm(false),
1301 _background(background),
1309 bool isAlardLupton = _ps->getAsString(
"kernelBasisSet") ==
"alard-lupton";
1310 bool usePca = _ps->getAsBool(
"usePcaForSpatialKernel");
1311 if (isAlardLupton || usePca) {
1312 _constantFirstTerm =
true;
1316 _nbases = basisList.
size();
1320 if (_constantFirstTerm) {
1321 _nt = (_nbases - 1) * _nkt + 1 + _nbt;
1323 _nt = _nbases * _nkt + _nbt;
1326 Eigen::MatrixXd mMat(_nt, _nt);
1327 Eigen::VectorXd bVec(_nt);
1338 LOGL_DEBUG(
"TRACE3.ip.diffim.SpatialKernelSolution",
1339 "Initializing with size %d %d %d and constant first term = %s",
1341 _constantFirstTerm ?
"true" :
"false");
1346 Eigen::MatrixXd
const& qMat,
1347 Eigen::VectorXd
const& wVec) {
1349 LOGL_DEBUG(
"TRACE5.ip.diffim.SpatialKernelSolution.addConstraint",
1350 "Adding candidate at %f, %f", xCenter, yCenter);
1354 Eigen::VectorXd pK(_nkt);
1356 for (
int idx = 0; idx < _nkt; idx++) { paramsK[idx] = 0.0; }
1357 for (
int idx = 0; idx < _nkt; idx++) {
1360 pK(idx) = (*_spatialKernelFunction)(xCenter, yCenter);
1363 Eigen::MatrixXd pKpKt = (pK * pK.transpose());
1366 Eigen::MatrixXd pBpBt;
1367 Eigen::MatrixXd pKpBt;
1369 pB = Eigen::VectorXd(_nbt);
1373 for (
int idx = 0; idx < _nbt; idx++) { paramsB[idx] = 0.0; }
1374 for (
int idx = 0; idx < _nbt; idx++) {
1377 pB(idx) = (*_background)(xCenter, yCenter);
1380 pBpBt = (pB * pB.transpose());
1383 pKpBt = (pK * pB.transpose());
1406 int mb = _nt - _nbt;
1408 if (_constantFirstTerm) {
1412 _mMat(0, 0) += qMat(0,0);
1413 for(
int m2 = 1; m2 < _nbases; m2++) {
1414 _mMat.block(0, m2*_nkt-dm, 1, _nkt) += qMat(0,m2) * pK.transpose();
1416 _bVec(0) += wVec(0);
1419 _mMat.block(0, mb, 1, _nbt) += qMat(0,_nbases) * pB.transpose();
1424 for(
int m1 = m0; m1 < _nbases; m1++) {
1426 _mMat.block(m1*_nkt-dm, m1*_nkt-dm, _nkt, _nkt) +=
1427 (pKpKt * qMat(m1,m1)).triangularView<Eigen::Upper>();
1430 for(
int m2 = m1+1; m2 < _nbases; m2++) {
1431 _mMat.block(m1*_nkt-dm, m2*_nkt-dm, _nkt, _nkt) += qMat(m1,m2) * pKpKt;
1436 _mMat.block(m1*_nkt-dm, mb, _nkt, _nbt) += qMat(m1,_nbases) * pKpBt;
1440 _bVec.segment(m1*_nkt-dm, _nkt) += wVec(m1) * pK;
1445 _mMat.block(mb, mb, _nbt, _nbt) +=
1446 (pBpBt * qMat(_nbases,_nbases)).triangularView<Eigen::Upper>();
1447 _bVec.segment(mb, _nbt) += wVec(_nbases) * pB;
1471 for (
int i = 0; i < _nt; i++) {
1472 for (
int j = i+1; j < _nt; j++) {
1496 void SpatialKernelSolution::_setKernel() {
1505 for (
int i = 0; i < _nbases; i++) {
1510 "I. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % i % cNumber));
1512 kCoeffs[i] =
_aVec(i);
1515 std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList();
1525 for (
int i = 0, idx = 0; i < _nbases; i++) {
1529 if ((i == 0) && (_constantFirstTerm)) {
1534 "II. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1536 kCoeffs[i][0] =
_aVec(idx++);
1539 for (
int j = 0; j < _nkt; j++) {
1544 "III. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1546 kCoeffs[i][j] =
_aVec(idx++);
1560 for (
int i = 0; i < _nbt; i++) {
1561 int idx = _nt - _nbt + i;
1565 "Unable to determine spatial background solution %d (nan)") % (idx)));
1567 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)