New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DM-15011 Add ModelVisit/ModelChip options for photometry #96
Conversation
4d1df20
to
f4b92e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit worried about the design implications of this change: specifically, the way ConstrainedPhotometryModel
and ChipVisitPhotometryMapping
get initialized, and the latter's inheritance relationship with PhotometryMapping
, both seem like they could introduce bugs. Minor comments otherwise.
python/lsst/jointcal/testUtils.py
Outdated
@@ -50,6 +50,9 @@ def createTwoFakeCcdImages(num1=4, num2=4, seed=100): | |||
a square, to have sqrt(num) centroids on a grid. | |||
seed : `int`, optional | |||
Seed value for np.random. | |||
fakeCcdId : `int`, optional | |||
Sensor identifier to use for both CcdImages (they will still represent | |||
ccdId=12, as that is the only testdata that is included here). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't understand this. If I call this function with fakeCcdId=13
, will the images "still represent ccdId=12"? What does that mean?
(Also, this function seems like a bit of a violation of the "do one thing" rule...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've clarified the text, lets see if that helps.. I agree it's somewhat of a violation of that, but this is all just a way to produce fake (but more complicated than a mock!) datasets to feed to tests of Models.
python/lsst/jointcal/testUtils.py
Outdated
@@ -111,6 +114,9 @@ def createFakeCcdImage(butler, visit, ccdId, num, instFluxKeyName, | |||
Value to set for calibrationMean in the created PhotoCalib. | |||
photoCalibErr : `float`, optional | |||
Value to set for calibrationErr in the created PhotoCalib. | |||
fakeCcdId : `int`, optional | |||
If set, use this as the ccdId in the returned CcdImage, otherwise | |||
use ``ccdId``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This descriptionis ok, but the description of ccdId
itself is kind of confusing. If I set fakeCcdId
, what exactly do I need ccdId
for (besides "to somehow use with the Butler")?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point: it turns out I can remove the ccdId
arg completely, so I've done so, and added a few clarifying comments.
@@ -77,6 +77,10 @@ class ConstrainedPhotometryModel : public PhotometryModel { | |||
private: | |||
PhotometryMappingBase *findMapping(CcdImage const &ccdImage) const override; | |||
|
|||
// Which components of the model are we fitting? | |||
bool _fittingChips; | |||
bool _fittingVisits; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a matter of style, you should explicitly initialize these in the constructor(s).
@@ -76,33 +76,56 @@ ConstrainedPhotometryModel::ConstrainedPhotometryModel(CcdImageList const &ccdIm | |||
} | |||
|
|||
unsigned ConstrainedPhotometryModel::assignIndices(std::string const &whatToFit, unsigned firstIndex) { | |||
// TODO DM-8046: currently ignoring whatToFit: eventually implement configurability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this TODO no longer valid? Your code is still stringly typed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, but this particular TODO was related to the fact that the existing code ignored whatToFit
, which is now fixed.
src/ConstrainedPhotometryModel.cc
Outdated
mapping->setIndex(index); | ||
index += mapping->getNpar(); | ||
if (whatToFit.find("Model") == std::string::npos) { | ||
LOGLS_ERROR(_log, "assignIndices was called and Model is *not* in whatToFit"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error, or warning? You are continuing with a no-op. (Should that behavior be documented?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I've changed it to a warning and now return the input index. If the code is ever called without "Model", I believe things can continue from that state. This would be made better with some enums instead of string parsing (hence DM-8046).
src/PhotometryMapping.cc
Outdated
@@ -23,30 +23,49 @@ void ChipVisitPhotometryMapping::computeParameterDerivatives(MeasuredStar const | |||
|
|||
// NOTE: the chip derivatives start at 0, and the visit derivatives start at the last chip derivative. | |||
// This is independent of the full-fit indices. | |||
Eigen::Ref<Eigen::VectorXd> chipBlock = derivatives.segment(0, _chipMapping->getNpar()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the comment still belong here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, although the code that it applies to now lives inside the two if statements, instead of on the immediately-following lines. Suggestions on how to make that clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's wrong with
// NOTE: the chip derivatives start at 0. This is independent of the full-fit indices.
...
// NOTE: the visit derivatives start at the last chip derivative. This is independent of the full-fit indices.
_visitMapping->getTransfo()->computeParameterDerivatives(measuredStar.getXFocal(), | ||
measuredStar.getYFocal(), instFlux, visitBlock); | ||
visitBlock *= chipScale; | ||
if (_nParVisits > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No test of _visitMapping->isFixed()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no such thing as a fixed visitMapping in a ChipVisitMapping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible that you'd add it in the future but forget to update this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not.
@@ -198,7 +198,7 @@ class ChipVisitPhotometryMapping : public PhotometryMappingBase { | |||
_visitMapping(std::move(visitMapping)) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add explicit initialization of _nParChips
and _nParVisits
.
self.assertFloatsAlmostEqual(result, expect) | ||
|
||
def _computeChebyshevDerivative(self, star): | ||
"""Return the derivatives w.r.t. the Chebyshev components.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this factoring follow from the C++-side changes, or should it be a separate commit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... I did it to make test_setWhatToFit
easier to write, which is a test of the new C++ code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I would have probably made it a commit before the C++ one. Oh well. :/
tests/test_photometryMapping.py
Outdated
self.assertEqual(self.mappingCheby.getNpar(), 0) | ||
self.assertEqual(self.mappingCheby.getMappingIndices(), []) | ||
result = self.mappingCheby.computeParameterDerivatives(self.star1, self.instFlux) | ||
self.assertFloatsEqual(result, np.array([])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of code duplication here. Can you factor it out? It looks like you only need:
- which parts of the model are being fit
- the set of indices (should you be testing order-sensitive equality?)
- the (local) method used to compute the derivative, or (for maximum flexibility) the derivative itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I've refactored. And yes, order matters.
python/lsst/jointcal/testUtils.py
Outdated
@@ -111,6 +112,8 @@ def createFakeCcdImage(butler, visit, ccdId, num, instFluxKeyName, | |||
Value to set for calibrationMean in the created PhotoCalib. | |||
photoCalibErr : `float`, optional | |||
Value to set for calibrationErr in the created PhotoCalib. | |||
fakeCcdId : `int`, optional | |||
If set, use this as the ccdId in the returned CcdImage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider removing the "If set". Presumably the default value of 12 gets used instead of being a magic number for "unspecified"?
typedef std::map<VisitIdType, std::shared_ptr<PhotometryMapping>> VisitMapType; | ||
VisitMapType _visitMap; | ||
// The per-chip transforms that go into _chipVisitMap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So is _chipVisitMap
an optimization to avoid recomputing the composition? It might be good to explicitly spell out the self-consistency requirements (which I assume are enforced by ConstrainedPhotometryModel
).
7b768cd
to
85f99d5
Compare
refactor test_photometryMapping.py so that I can compute the chip and visit derivatives separately. The cfht ConstrainedPhotometryModel chi2 changed very slightly, which I can believe, as it starts with a different initial step.
85f99d5
to
10d889c
Compare
No description provided.