Skip to content
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

Merged
merged 2 commits into from Jul 19, 2018

Conversation

parejkoj
Copy link
Collaborator

@parejkoj parejkoj commented Jul 6, 2018

No description provided.

Copy link
Member

@kfindeisen kfindeisen left a 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.

@@ -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).
Copy link
Member

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...)

Copy link
Collaborator Author

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.

@@ -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``.
Copy link
Member

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")?

Copy link
Collaborator Author

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;
Copy link
Member

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.
Copy link
Member

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.

Copy link
Collaborator Author

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.

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");
Copy link
Member

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?)

Copy link
Collaborator Author

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).

@@ -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());
Copy link
Member

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?

Copy link
Collaborator Author

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?

Copy link
Member

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) {
Copy link
Member

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()?

Copy link
Collaborator Author

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.

Copy link
Member

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?

Copy link
Collaborator Author

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)) {}
Copy link
Member

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."""
Copy link
Member

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?

Copy link
Collaborator Author

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.

Copy link
Member

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. :/

self.assertEqual(self.mappingCheby.getNpar(), 0)
self.assertEqual(self.mappingCheby.getMappingIndices(), [])
result = self.mappingCheby.computeParameterDerivatives(self.star1, self.instFlux)
self.assertFloatsEqual(result, np.array([]))
Copy link
Member

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

Copy link
Collaborator Author

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.

@@ -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.
Copy link
Member

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.
Copy link
Member

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).

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.
@parejkoj parejkoj merged commit 82b7855 into master Jul 19, 2018
@ktlim ktlim deleted the tickets/DM-15011 branch August 25, 2018 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants