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

Fix bug that was only using row dither for hot pixel region check #195

Merged
merged 13 commits into from
Dec 18, 2018

Conversation

jeanconn
Copy link
Contributor

@jeanconn jeanconn commented Dec 14, 2018

Fix bug that was only using row dither for hot pixel region check

get_ax_range was ignoring the supplied value of "extent" and using row_extent always. This is an issue for observations with asymmetric dither.

get_ax_range is still ugly, but I've moved it to top level so I can use it equivalently from the guide reporting.

Closes #194

@taldcroft
Copy link
Member

This is related to #125 (where I consider imposters to be a type of spoiler). Unit test with a synthetic star catalog and synthetic dark current is needed. Probably worth adding a quick unit test of get_ax_range as well.

proseco/guide.py Outdated
minus = int(np.floor(n - extent))
plus = int(np.ceil(n + extent))
if (np.floor(n) != np.ceil(n)):
if n - np.floor(n) > .5:
Copy link
Member

Choose a reason for hiding this comment

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

Never write .5 always 0.5.

proseco/guide.py Outdated
"""
Given a float pixel row or col value and an integer pixel "extent",
return a range for the row or col that is divisible by 2 and contains
at least the requested extent
Copy link
Member

Choose a reason for hiding this comment

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

Period at the end and newline.

proseco/guide.py Outdated
"""
minus = int(np.floor(n - extent))
plus = int(np.ceil(n + extent))
if (np.floor(n) != np.ceil(n)):
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 this logic. Basically you want plus and minus to be even, right? So would this work?

# Ensure plus and minus are both even, expanding the range as needed.
if minus % 2 != 0:
    minus -= 1
if plus % 2 != 0:
    plus += 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We want (plus - minus) to be even. If you ensure that both are even (or odd) you do win that, but you can end up adding extra pixels to both ends that really aren't going to be in the 8x8.

Copy link
Contributor Author

@jeanconn jeanconn Dec 14, 2018

Choose a reason for hiding this comment

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

With the logic that is in there now, the initial

minus = int(np.floor(n - extent))
plus = int(np.ceil(n + extent))

guarantees you have a odd range (for real float values not exactly at the pixel boundary), and then it adds one more pixel to the side closest to the offset of the star within the center pixel (IIRC).

Copy link
Member

Choose a reason for hiding this comment

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

If this is about figuring out the readout window then can we use the usual logic for defining a readout window?

n_int = int(round(n))  # for `n` in edge pixel coords
plus = n_int + extent
minus = n_int - extent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The extent is a float value. If you want to round it up, this works too, but will get extra pixels.

Copy link
Contributor Author

@jeanconn jeanconn Dec 14, 2018

Choose a reason for hiding this comment

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

Where's the usual logic for defining a readout window? If I should always be taking one off the minus or adding one to the plus anyway, that's fine, but practically, I was trying not to add many extra pixels while still making it possible to bin 2x2. If that's just too ugly we can do something different, but may end up with regression test changes.

Copy link
Member

Choose a reason for hiding this comment

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

Here's one implementation of the "usual logic":
https://github.com/sot/chandra_aca/blob/master/chandra_aca/aca_image.py#L451
I'm sure you find it in annie as well.

I don't quite follow what you are saying, but the 3 lines I wrote will always give the minimal set of pixels that are centered on n and can be binned 2x2. I suspect it is exactly equivalent to what you wrote.

Copy link
Contributor Author

@jeanconn jeanconn Dec 14, 2018

Choose a reason for hiding this comment

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

I'm still confused. extent is meant to have 4 pixels for the 8x8 image and, generally, plus 1.6 pix for 8x8 dither. So plus = n_int + 5.6 doesn't quite work, but if I round up in both directions again that probably works.

So, for a star with nominal row=0.7 in edge coordinates, what should the dithered pixel region be in row?

-6 to 6
or
-5 to 7

Because I thought -5 to 7 was the right answer, but I didn't have the usual logic as my reference.

@taldcroft
Copy link
Member

The docstring said extent is an integer, and that does make a difference here. I was predicating my comments on that assumption. For non-integer values it might be a different story.

@jeanconn
Copy link
Contributor Author

jeanconn commented Dec 14, 2018

Oops. Thanks Tom. Introduced docstring bug fixed.



def test_get_ax_range():
# Confirm that the ranges from get_ax_range are reasonable for a variety of
Copy link
Member

Choose a reason for hiding this comment

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

Use docstrings for tests so they show up in API docs.


def test_edge_star():
"""
Add stars right at row and col max for 8" dither.
Copy link
Member

Choose a reason for hiding this comment

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

This test is good but it seems like it does not actually test the bug fix related to get_ax_range. That would happen with hot pixel imposters right?

Also in both this test and a synthetic hot pixel test, document the exact source of the magic numbers (e.g. 495.3). I'm never sure whether it is best to have test values like this hardcoded, so it gives a visible regression if characteristics change, or have them computed in the test so tests continue passing. If you don't care then I'd say the latter.

        row_max = CCD['row_max'] - (CCD['row_pad'] + CCD['window_pad'] + r_dith_pad)
        col_max = CCD['col_max'] - (CCD['col_pad'] + CCD['window_pad'] + c_dith_pad)

Also in both tests it would be best to use asymmetric dither, esp for imposters since that was the original point of the bug fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I was working on a new test of hot pix imposters Friday but didn't finish. Will get it in. And sure, documenting exact source of the numbers sounds good (I at least left a note about nominal dither being required for the test setup, but can also recalculate it directly here. Figured it was unlikely we'd change CCD characteristics without needing to update all the tests anyway.). For the edge case test, I don't think it matters if the test is done with asymmetric dither or not, but fine to do so. For my specific bug also need to test with the "large" dither in each axis.

proseco/guide.py Show resolved Hide resolved
@jeanconn
Copy link
Contributor Author

I converted "n" to "rc" in get_ax_range, but also didn't like that the use of "ceil" in the way that get_ax_range was being called effectively meant that ACIS observations got a 0.4 arcsec pad, but HRC observations got no padding. So I added a pad to each and got rid of that use of ceil. Was that too much @taldcroft ?

dither_pix_pad = 0.4

# Minimum imposter mag (if dark current is 0 set explicitly to this value)
min_imposter_mag = 20.0
Copy link
Member

Choose a reason for hiding this comment

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

This is actually the max value of imposter_mag. Otherwise this and the code that uses it are OK.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hah. I should have used a variant on faint.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How about "imposter_mag_for_zero_dark"?

Copy link
Member

Choose a reason for hiding this comment

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

Fine. Plan B would be to replace pixmax with np.clip(pixmax, 1.0, None) in the offending line, add a code comment, and be done with it. I somehow feel like characteristics should be reserved for constants that have a discernible algorithmic impact. But that is my style and not necessarily correct. Your choice. FYI, count rate of 1.0 is very nearly 20th mag. 😄.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. I like that better. And yes, I saw that count rate of 1 is basically 20th mag. I considered just setting pixmax to 1.0 before starting the loop over the sums, but didn't want to just add 1.0 in general. Your clip is better.

@jeanconn
Copy link
Contributor Author

OK, so maybe this is now done? I didn't see feedback on the 0.4 pad I added to (the HRC) dither boxes.

I did not update version figuring that could go in after merging (and after any other updates).

@jeanconn jeanconn merged commit 74e94eb into master Dec 18, 2018
@jeanconn jeanconn deleted the extent branch December 18, 2018 01:52
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.

2 participants