Repository navigation
fits.PrimaryHDU doesn't properly initialize from scaled data - #2305
Conversation
|
I'm not sure I fully follow your example, as in what you were trying to do originally (what the inputs and expected outputs were) and what you got instead. All of the behavior shown in the example is by design, though admittedly potentially confusing. Also worth noting that what you're really trying to do here is something involving unsigned ints--at this point by fair the most used usecase for BZERO. I need to work more on making unsigned int support just more transparent because it's really absurd that it isn't. |
|
By the way, perhaps what you're missing is the ETA: Ah, okay. One other issue here--if creating a new HDU object with unsigned integer data it should probably go ahead and put the appropriate BZERO value in the header upon initialization. Is that what you're getting at here? |
Yes, sorry that wasn't clear. That is the only problem I was trying to report. More detail: Given a should return If I ask I would expect that I should never get unscaled data with no 'BZERO'.
I was trying to do something that, in retrospect, was nonsensical :-/ : allowing the user to ask that data not be scaled when initializing a In my defense, the immediate goal was allowing keywords to pass through the CCDData reader to |
|
I think that all makes sense now. Agreed this specific case should be handled better. |
|
Still need to give this some thought, and some more explanation of what you're doing might be useful. The problem with the current code is this: When you instantiate a Because of this, the Unfortunately, what I'm referring to as "structural" keywords also includes BSCALE and BZERO. If given an array and a header with BSCALE/BZERO, where their association is unknown, it's often completely ambiguous if and how those scale keywords should be applied to the input data array. Maybe it's already been scaled according to those parameters. Maybe it hasn't. Maybe the input header came from a completely different HDU and the user just wanted to copy the metadata, but BSCALE/BZERO just came along for the ride unintentionally. In other words, the header argument should not have any effect on how the data argument is interpreted. I think that was the original intent in the current design. Now there is one small set of cases where it's less ambiguous, and that's the unsigned int case. But say we're given an array of uint16--if all the values in the array are < 32768, then the array can just as easily be stored in FITS as a normal int16 array. It's only when given an array of uint16 containing values >= 32768 that the pseudo-unsigned int workaround is necessary. And I believe that case should just work transparently. Users should be able to store/retrieved unsigned integer arrays from a FITS file without having to fuss around with scaling or headers or anything like that. I'm not sure if that would help with your problem though... |
|
Okay, here's an example that I think illustrates what can and should be fixed for now (before I go about completely overhauling uint support). I think this is almost identical to the example you gave, but going through it myself helped understand: So in short, the initial |
|
I agree that your examples illustrates the essential problem: the header can end up in a state that, applied to the data, results in incorrect data values. Thanks for the summary of how the header initialization is handled -- useful to know for ccdproc. |
astropy/astropy#2305 by ensuring that the method (_ImageBaseHDU.update_header) responsible keeping an HDU's header in sync with the data it represents, also makes the necessary updates to ensure that the header contains the correct BZERO value for pseudo-unsigned integers.
astropy#2305 by ensuring that the method (_ImageBaseHDU.update_header) responsible keeping an HDU's header in sync with the data it represents, also makes the necessary updates to ensure that the header contains the correct BZERO value for pseudo-unsigned integers.
|
@mwcraig If you'd like, would you please try out the attached change and see how that works for your needs? It's a one-line fix, hopefully. |
|
@embray -- I don't think this fixes...and it appears to break in some cases the current (correct) behavior for unsigned int images; I'm afraid I may be confusing the issue! I'll try to clarify the issue below, but want to emphasize first that the original use case I had for this issue is gone, so there is no urgency to getting a fix on my end. In case this is tl;dr -- would it be helpful if I wrote a couple tests that demonstrate what I see as the problems? Looking over your example again, I think it demonstrates a separate issue than the one I originally reported. Assume that you have already created So far so good -- the header and data are consistent in the sense that to get the physical data values from the stored data values I use BZERO/BSCALE from the header, If you open the same file but allow the data to be scaled this happens (there is no error in what is immediately below): Now to the case in your example, opening the data file with the I think this is an error because it is no longer the case that
I think the answer here should have been no...my bad. Doing so leads to the same error as opening with I'm not sure it is the same error that I reported initially, though. In that case my expectation was that the handling of data scaling when creating an HDU with Here the error is that it is no longer possible to reconstruct the physical values because |
|
Ah, the third case you mentioned I agree is confusingly inconsistent with the others. But I think it's somewhat intentional that it's treated differently with unsigned ints. The reason being if you read the file with I guess maybe a more consistent approach would be to add BZERO to the header before writing and then remove it again afterward. But having in the header reflects what will be written when the file is written to a file. On the other hand with arbitrary BSCALE/BZERO, those are left out of the header because they will not be used when writing the file (unless I have some ideas to improve the situation somewhat, but no matter what it has to be a little confusing. The area that can be improved most (and honestly that's most common anyway) is with unsigned ints. I think as it is this already works pretty okay. The only major change is that And yes, |
|
Oh, and as for your last example, this is exactly as expected. When you call it has no way of knowing that that data was originally associated with that header. The BSCALE/BZERO are stripped from the header and are no longer relevant. I agree this is a problem though. This would be a good place to mention what I'm planning to do to address this, and some other issues. I think I've mentioned elsewhere too that what is really needed is a |
|
Would it make sense, then, to drop the arguments |
|
Possibly, eventually, but only as part of a more significant refactoring. |
|
In the meantime I'm not entirely clear where to go with this. I agree the behavior is confusing, but other than the one tweak I made in this PR it's all by design, and somewhat by necessity. There's no real consistent way to deal with these issues of FITS. In particular, the uint case needs to be treated as distinct from arbitrary "scaled" data. Really |
|
I would leave it as it is (even without the tweak) -- ultimately, my confusion came from the existence of the scaling arguments in I do regret not suggesting for the A&C FITS limitations paper that FITS cannot even handle simple data types like unsigned int.... |
|
Hah, that's a good point. It should have been in there. In fairness, it would be an easy enough thing to fix in FITS. It mystifies me that they haven't (we could add 64-bit ints, but not unsigned ints?) I think I am going to include this change though because it is more consistent with the intended behavior, regardless of how confusing the intended behavior is. |
|
With this passing I'm going to go ahead and merge as is. It's no less confusing but it is more in the direction of where I want to go with this. |
fits.PrimaryHDU doesn't properly initialize from scaled data
fits.PrimaryHDU doesn't properly initialize from scaled data
astropy#2305 by ensuring that the method (_ImageBaseHDU.update_header) responsible keeping an HDU's header in sync with the data it represents, also makes the necessary updates to ensure that the header contains the correct BZERO value for pseudo-unsigned integers.
Creating a new
PrimaryHDUfrom an HDU containing scaled data results in a new HDU with the data scaled butBITPIXdropped from the header.To reproduce: