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

Tickets/DM-42228: add donut quality check #222

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from

Conversation

suberlak
Copy link
Contributor

No description provided.

@@ -14,6 +22,8 @@ Version History

* Added unit test directly comparing ``ImageMapper`` optical models to Batoid raytracing.

=======
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed, possibly this is left over from a merge conflict?

@@ -153,12 +153,23 @@ def run(
units=self.config.units,
saveHistory=self.config.saveHistory,
)
# Exclude stamps that are not effective
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you create a config and make this an optional step? It would be easier for debugging things in the future if we can easily turn this on and off when running the pipeline.


# Loop over donut stamps and estimate Zernikes
zkList = []
histories = dict()
for i, (donutExtra, donutIntra) in enumerate(
zip(donutStampsExtra, donutStampsIntra)
zip(donutStampsExtraSelect, donutStampsIntraSelect)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we keep track of which Zernike estimates go with which donut in the end? I think we discussed adding in flags to the CalcZernikesTask to identify?

@@ -174,6 +175,14 @@ def factory(cls, stamp_im, metadata, index, archive_element=None):
if metadata.get("BANDPASS") is not None
else ""
),
# "EFFECTIVE" is a measure of entropy-based information content
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add something here to indicate this is a signal-to-noise effectiveness measure? Otherwise it's pretty vague.

@@ -179,6 +181,17 @@ def getBandpasses(self):
"""
return [stamp.bandpass for stamp in self]

def getEffectives(self):
"""
Get the effectiveness measure for each stamp.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also can you add something indicating this is related to SNR?

@suberlak suberlak requested a review from jbkalmbach May 16, 2024 23:54
Copy link
Member

@jbkalmbach jbkalmbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it needs any really extensive changes. Marking as request changes because there's a lot more tests I'd like to see added and also the existing tests don't seem to be passing on Jenkins.

eff = False

# Return the actual entropy value if needed
if self.returnEntro:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a new test to check this works correctly?

default=5000,
doc=str(
"The S/N threshold to use (keep donuts only above the threshold)."
+ "The default S/N = 5000 corresponds to the default entropy threshold (3.5)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why S/N = 5000 is necessarily equivalent to an entropy of 3.5. Where does this come from?


selectWithSignalToNoise = pexConfig.Field(
dtype=bool,
default=False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If both selectWithSingalToNoise and selectWithEntropy are both True what is the functionality when it passes only one test? Is it logical and or does one take priority? Please add some more documentation explaining what happens in that situation as well as adding tests to verify that the expected behavior is what you see.

@@ -120,13 +165,75 @@ def run(
return pipeBase.Struct(
outputZernikesRaw=np.full(19, np.nan),
outputZernikesAvg=np.full(19, np.nan),
donutsExtraQuality=[],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should be empty dataframes. You should add a test that checks the pipeline runs with empty content because I think this should fail since it doesn't match the output described in the connections class.

)
# Which donuts to use for Zernike estimation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic (down to line 226) should be moved to its own function. This needs tests as well and moving it to its own function will make it simpler to test.

@@ -329,6 +427,21 @@ def cutOutStamps(self, exposure, donutCatalog, defocalType, cameraName):
xCornerList = list()
yCornerList = list()

# Centroid shift
drCentroidList = list()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to separate dx, dy as mentioned in today's AOS meeting.

@@ -435,14 +566,65 @@ def cutOutStamps(self, exposure, donutCatalog, defocalType, cameraName):
stampsMetadata["DFC_DIST"] = np.array(
[instrument.defocalOffset * 1e3] * catalogLength
)
# Save the donut flux as magnitude
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when you have this branch set up and you try to load butler datasets with old donut stamps? Do you run into errors?

@@ -159,32 +161,25 @@ def run(
camera: lsst.afw.cameraGeom.Camera,
) -> pipeBase.Struct:
cameraName = camera.getName()
# The order of donut catalogs is the same
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these changes should be rolled back. When running interactively a user might not know that they should put in extra, intra in order. Maybe what we should do is make an issue to find a way to force the donutCatalogs to have the same test as the exposures?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be as simple as including the detector name in our donut catalogs.

"SN_SELECT",
"FINAL_SELECT",
]
np.testing.assert_array_equal(np.sort(colnames), np.sort(desired_colnames))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above we should test the actual logic inside the selection code.

# test the calculation of SN
sn_values = [25.88952737640593, 39.90181466115093, 33.6410205949]
sn_calculated = donutStamps.metadata.getArray("SN")
np.testing.assert_array_almost_equal(sn_values, sn_calculated, decimal=4)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test that runs the pipeline and verifies all the metadata gets stored in the butler and when you pull the donut stamp from the repository that it still has all the metadata you added? I wonder if because the DonutStamps class doesn't know about these if they get loaded correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants