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-41490: Recover WCS for input with astrometry failures #40
Conversation
cf3dd58
to
f88401a
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.
There's no test of this functionality: you should be able to make a trivial visitSummary that has a None (or missing) WCS for one detector and test with that.
# This extension does not have information necessary for | ||
# fit. Skip these detections. |
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 not following this comment (I don't know what an extension is in this context). By "these detections", do you mean "this detector/visit"?
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.
"extension" is the gbdes
term for one detector from one visit, and it's used throughout the gbdes
task. I can change this line to "Skip the detections from this detector for this visit" to make it more clear.
# This extension does not have information necessary for | ||
# fit. Skip these detections. |
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.
Same comment as above, with the aded question of why this is duplicated 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.
This is duplicated because the sources get loaded two times--once when the source association is done, and again when they are added to the model fitting object.
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 clicked the button too soon earlier.
# This extension was not fit, but try to recover WCS | ||
genericElements = mapTemplate["EXPOSURE/DEVICE/base"]["Elements"] | ||
mapElements = [] | ||
instrument = visitSummary[0].getVisitInfo().getInstrumentLabel() |
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.
You should be able to do summary.visitInfo.instrumentLabel
, instead of using getters.
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.
summary.visitInfo
doesn't work, but I can do visitSummary[0].getVisitInfo().instrumentLabel
.
elements = mapTemplate[component]["Elements"] | ||
for element in elements: | ||
for generic, specific in { | ||
"BAND": instrument, |
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 instrument
really a thing to substitute for band
?
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.
It probably shouldn't be, but these lines are trying to replicate how gbdes
names mappings, and the instrument name is what ends up here (probably due to this line: https://github.com/lsst/gbdes/blob/4efbc7097dc222cb35d22f8aed79572413aa1a97/include/Instrument.h#L21). A near-term item on my to-do list is to switch to fitting multiple bands at once, so this will probably be addressed there.
genericElements = mapTemplate["EXPOSURE/DEVICE/base"]["Elements"] | ||
mapElements = [] | ||
instrument = visitSummary[0].getVisitInfo().getInstrumentLabel() | ||
for component in genericElements: |
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 really don't understand what this nested set of loops is supposed to do. I assume it's a gbdes internals thing?
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.
Sort of...this loop goes through the generic definitions for the mappings that take you from pixels to sky and uses those to get the names for the maps for a specific extension (i.e. visit/detector). I spent a lot of time trying to get gbdes
to do this itself, but couldn't manage it, so this is my replication of how gbdes
makes the names.
if mapName in wcsf.mapCollection.allMapNames(): | ||
mapElements = wcsf.mapCollection.orderAtoms(f"{mapName}/base") | ||
else: | ||
# This extension was not fit, but try to recover WCS |
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.
Assuming "extension" means "detector/visit": if a detector/visit wasn't fit, how could there be a WCS?
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, "extension" means "detector/visit". The detector part of the model is fixed by the sources from this detector on other visits, and the visit part of the model is fixed using the other detectors for the visit. Actually, this makes me realize I need to add a check so that this doesn't fail when there is only one detector.
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.
Scratch the part about what happens when there is only one detector. That will be caught at line 1354.
self.log.warning( | ||
"WCS is None for visit %d, detector %d: this extension will be dropped.", | ||
visit, | ||
detector, | ||
) | ||
continue |
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.
Should this be a warning, or an info-level message? Also, saying "extension" in the log is unhelpful for anyone who doesn't know the gbdes internals.
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 think a warning is right (from the dev-guide: "WARNING: for conditions that may indicate a problem but that allow continued execution"). I think there should be a note of caution for the resulting WCS.
I changed the message to say "...this extension (visit/detector) will be dropped."
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.
Do you have a way to flag the WCSs that are "reconstructed" in this case in the output, to warn users? A warning message may be appropriate here, but it's not sufficient to tell people that the output WCS is potentially unreliable.
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, neither the WCSs nor the visitSummary tables have a flag for WCS quality. The WCS fit will have higher uncertainty, as it would if there were very few stars to fit, and Eli and I have talked a bit about how to propagate this information.
Thanks for the review @parejkoj. I'll add a unit test and update the PR. |
6941558
to
0509645
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.
You really should pull the contents of some of these for-loops into separate functions. That will make it easier to parse, and at least in one case here, you won't have duplicated code.
)[0] | ||
) | ||
if len(findExtension) == 0: | ||
# This extension does not have information necessary for | ||
# fit. Skip the detections from this detector for this | ||
# visit. | ||
continue | ||
extensionIndex = findExtension[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.
Most of the contents of this for-loop are the same as the loop at line 1000: looks like you should have a function for the internals here that gets called in both places.
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 looked at this for a while and decided that the two loops are different enough that a function is not going to improve clarity much. I did implement a _find_extension_index()
method for a part of the loop that is repeated.
for component in genericElements: | ||
elements = mapTemplate[component]["Elements"] | ||
for element in elements: | ||
element = element.replace("BAND", str(instrument)) |
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 think you need a comment here as to why band and instrument are being mixed.
) | ||
|
||
# Check that the fit WCS for the extension with input WCS=None returns | ||
# finite sky values. |
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.
Should it return finite sky values, or correct sky values? Is the test dataset not large enough to get a reasonable fit in this case?
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.
The test data is simulated without the missing WCS, so we don't expect to be able to recover the same input in this test. It's possible to do a whole new simulation, but I don't think it's worthwhile in this case.
c345a11
to
ac40fb2
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.
Thanks for the cleanups.
No description provided.