-
Notifications
You must be signed in to change notification settings - Fork 8
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
Add unit tests for ImageMapReduce task #45
Conversation
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.
Several changes requested in comments. I haven't looked at the actual functional code that this is testing, but this test structure makes sense to me. I do feel like there should be at least one more test that does something a bit more complicated: for example, although you set the PSF of the exposure, it doesn't look like it actually impacts the results of any of the tests.
tests/testImageMapReduce.py
Outdated
@@ -0,0 +1,243 @@ | |||
from __future__ import absolute_import, division, print_function | |||
from builtins import range | |||
from past.builtins import basestring |
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 need the basestring import here? I don't see it used.
tests/testImageMapReduce.py
Outdated
|
||
|
||
class TestImageMapperSubtaskConfig(ImageMapperSubtaskConfig): | ||
"""! |
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.
Please switch to pydoc style for all python docstrings here, and below: https://developer.lsst.io/docs/py_docs.html
tests/testImageMapReduce.py
Outdated
_DefaultName = "ip_diffim_TestImageMapperSubtask" | ||
|
||
def __init__(self, *args, **kwargs): | ||
"""! Create the image gridding subTask |
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 docstring for __init__
goes in the class-level docstring.
tests/testImageMapReduce.py
Outdated
@param *args arguments to be passed to lsst.pipe.base.task.Task.__init__ | ||
@param **kwargs keyword arguments to be passed to lsst.pipe.base.task.Task.__init__ | ||
""" | ||
ImageMapperSubtask.__init__(self, *args, **kwargs) |
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 don't think you even need this __init__
, if you're not doing anything besides calling super.
tests/testImageMapReduce.py
Outdated
self.exposure = afwImage.ExposureF(128, 128) | ||
self.exposure.setPsf(measAlg.DoubleGaussianPsf(11, 11, 2.0, 3.7)) | ||
mi = self.exposure.getMaskedImage() | ||
mi[:, :] = 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.
Huh. I just looked, and didn't see an Exposure constructor that would assign a value to the entire maskedImage. Could you ask slack#dm if such a constructor exists, and if not file a ticket against afw?
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.
For exposures, that would be tricky (image, variance, masks, psfs, etc.) To me, that would only make sense if it explicitly sets everything to zero. I am not sure if the default empty constructor guarantees that (probably not, for speed), so I just do it explicitly 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.
It's good we brought this up: https://jira.lsstcorp.org/browse/DM-9593
tests/testImageMapReduce.py
Outdated
|
||
mn = newArr.mean() | ||
self.assertClose(mi.getImage().getArray().mean(), mn - expectedVal) | ||
self.assertClose(mn, expectedVal) |
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 comments as above about testing the full array.
tests/testImageMapReduce.py
Outdated
|
||
task = ImageMapReduceTask(config) | ||
boxes = task._generateGrid(self.exposure) | ||
if len(boxes[0]) > 1000: # bypass to prevent slow testing |
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.
How much slower is it? What bit of code makes it slow? Seems like a potentially interesting possible failure mode (having many boxes).
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 is not a failure; it would just lead to a very long unit test run which I figure we want to avoid for regular CI. As it turns out I adjusted the parameters to be more realistic and now this case never happens. But I will leave it in there just in 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.
I'm uncomfortable with a "just in case" thing that disables tests. If you've tweaked the parameters so that it doesn't happen, just get rid of it. If a future person re-changes the parameters such that the test takes a long time, they can figure out what to do then.
tests/testImageMapReduce.py
Outdated
for scaleByFwhm in (False, True): | ||
config.scaleByFwhm = scaleByFwhm | ||
for gsx in range(51, 1, -10): | ||
config.gridStepX = config.gridSizeX = gsx |
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 the gridSize and gridStep always be equal? If not, you should have at least one test where they're different.
tests/testImageMapReduce.py
Outdated
expectedVal = 1. | ||
config.mapperSubtask.addAmount = expectedVal | ||
|
||
for scaleByFwhm in (False, True): |
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'd put the contents of one of these loops (maybe the inner-most one?) in a separate method, say _testGridValidity(self, scaleByFwhm, gridX, gridY)
, and then call that. The nested loops are a bit unwieldy.
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 also concerns me that scaleByFwhm doesn't change any of the results. You should probably have a test where that value matters, otherwise it might be doing nothing and you'd never know.
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.
scaleByFwhm changes the grid parameters, but here we simply want to ensure that given a set of input grid parameters, we don't fail and the final output image is not wrong. Thus the fact that they are the same is a good thing. That said, you're right that we should check the grid itself. I'll add a test for that.
tests/testImageMapReduce.py
Outdated
""" | ||
addAmount = pexConfig.Field( | ||
dtype=float, | ||
doc="""Amount to add to image""", |
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.
Don't need triple quotes 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.
More comments on the latest commit.
tests/testImageMapReduce.py
Outdated
Bounding box of original exposure (not used here) | ||
kwargs | ||
Arbitrary keyword arguments (ignored) | ||
------- |
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.
Don't need line here, just under Returns
.
tests/testImageMapReduce.py
Outdated
Bounding box of original exposure (not used here) | ||
kwargs | ||
Arbitrary keyword arguments (ignored) | ||
------- |
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.
Another unnecessary line.
tests/testImageMapReduce.py
Outdated
boxes = task._generateGrid(self.exposure) | ||
ind = 0 if scaleByFwhm else 1 | ||
lenBoxes[ind] = len(boxes[0]) | ||
if len(boxes[0]) > 1000: # bypass to prevent slow testing |
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 still don't like needing this if statement, particularly if you've reworked it to not result in such a large number of boxes.
tests/testImageMapReduce.py
Outdated
mn = newArr.mean() | ||
self.assertClose(mi.getImage().getArray().mean(), mn - expectedVal) | ||
self.assertClose(mn, expectedVal) | ||
if scaleByFwhm: |
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 suggests to me that you should have two separate test methods, one for scaleByFwhm=True
and the other for False
.
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.
That will lead to a lot of code duplication. Plus I want to compare the results of scaleByFwhm=True
vs. False
.
tests/testImageMapReduce.py
Outdated
|
||
def testGridValidity(self): | ||
"""!Test sample grids with various spacings and sizes and other options. | ||
"""Test sample grids with various spacings and sizes and other options. | ||
|
||
Try to see if we can break it. |
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 sure this line of the docstring is actually helpful? Maybe if you defined what this could break, and how?
ce87058
to
31b7b1b
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 added tests. I'll bet the coverage is a fair bit better now.
A few comments about preferred assert choices.
tests/testImageMapReduce.py
Outdated
mi = self.exposure.getMaskedImage() | ||
isnan = np.isnan(newArr) | ||
if not withNaNs: | ||
self.assertTrue(np.sum(isnan) == 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.
Don't you want self.assertEqual(np.sum(isnan), 0)
?
tests/testImageMapReduce.py
Outdated
@@ -130,58 +142,122 @@ class ImageMapReduceTest(lsst.utils.tests.TestCase): | |||
"""A test case for the image gridded processing task | |||
""" | |||
def setUp(self): | |||
self._makeImage() |
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.
Since you're using msg=
now, probably set self.longMessage=True
, to get both your custom messages, and the default unittest ones.
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.
Apparently True is the default, but I'll set it explicitly anyway.
self.testAverageVersusCopy(withNaNs=False) | ||
self.testAverageVersusCopy(withNaNs=True) | ||
|
||
def testAverageVersusCopy(self, withNaNs=False): |
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 should have a preceeding _
, otherwise it'll get run by the test suite on its own.
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.
Oops, missed that.
tests/testImageMapReduce.py
Outdated
newMI = newExp.getMaskedImage() | ||
newArr = newMI.getImage().getArray() | ||
mi = self.exposure.getMaskedImage() | ||
isnan = np.isnan(newArr) | ||
if not withNaNs: | ||
self.assertTrue(np.sum(isnan) == 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.
Another assertEqual
here.
tests/testImageMapReduce.py
Outdated
newMA1 = newMI1.getImage().getArray() | ||
isnan = np.isnan(newMA1) | ||
if not withNaNs: | ||
self.assertTrue(np.sum(isnan) == 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.
assertEqual
self.assertTrue(np.sum(isnan) == 0) | ||
newMA2 = newMI2.getImage().getArray() | ||
|
||
self.assertFloatsAlmostEqual(newMA1[~isnan], newMA2[~isnan]) |
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.
👍
tests/testImageMapReduce.py
Outdated
newMI = newExp.getMaskedImage() | ||
newArr = newMI.getImage().getArray() | ||
mi = self.exposure.getMaskedImage() | ||
isnan = np.isnan(newArr) | ||
self.assertTrue(np.sum(isnan) == 0, msg='Failed NaN (%d), on config: %s' % |
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.
assertEqual
again
tests/testImageMapReduce.py
Outdated
msg='Failed on config: %s' % str(config)) | ||
|
||
self.assertTrue(lenBoxes[0] < lenBoxes[1], msg='Failed on config: %s' % str(config)) | ||
self.assertTrue(lenBoxes[0] < lenBoxes[1], msg='Failed lengths on config: %s' % |
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.
self.assertLess(lenBoxes[0], lenBoxes[1], ...)
Final commit of the unit test in this PR was instead moved to PR #46, to be merged alongside ImageMapReduceTask. |
No description provided.