-
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
WCS information for SIP files doesn't survive write/read round trip to FITS file. #8
Comments
I fully expect SIP, TPV and ZPX to be working and I worry that you feel you have to work around issues with all of these formats. Thanks for the report. @dsberry will look into it. |
I think the error is in the return value from fc2.write(wcs). AST can read SIP headers but has never supported the writing of SIP headers. In principle, fc2.write(wcs) is supposed to return zero if the pixel to intermediate world coord transformation is non-linear by more than 0.1 of a pixel over the area of the image. The sample SIP file has a pixel size of around 1.2 arc-seconds, and so an error of 3 arc-seconds corresponds to a couple of pixels, and so fc2.write(wcs) should definitely return zero. I'll look into it. Do you have a need for AST to write SIP headers, or is it just that you want the test to fail correctly? |
I don't have a specific need for AST to write FITS headers correctly using the standard FITS formats. I think most of the time, it is sufficient that AST can write its own proprietary format correctly. In GalSim, I just have it try the FITS-WCS encoding first, since if that works, it's probably a bit more useful for some users. Most of the time in GalSim if a user is dealing with SIP (or other PV-type) WCS's, they will be reading them from an existing data file, and that works just fine with AST. And if they do generate a new image that uses one of these, they can probably either just copy over an existing header into the output if they want the output to be FITS-standard or use AST (directly or via GalSim) to read it back in, so the proprietary format will be acceptable. If some user down the line wants AST to write correct SIP headers in the normal FITS format, I'll let them post that feature request. :) |
I think I've fixed the issue in AST that caused fc2.write(wcs) incorrectly to write out a header. I've uploaded a new version of pyast (3.9.0) to pypi which includes the new version of AST (8.0.5). |
Hm. When I run the script I posted above, it still tells me that |
It did output success=0 for me, but it seems that was due to a foul up on my part regarding pyast versions on my local machine. Sorry. Having sorted myself out, I now see success=1. This is caused by the fact that the "fc2" fitschan does not contain values for NAXIS1 and NAXIS2 when you do "fc2.write(wcs)", so the write() method does not know how big the pixel grid is. In such cases it uses a default of 100 pixels on each axis when determining the extent of the non-linearity of the WCS. In this particular case, the non-linearity over 100 pixels does not exceed the limit, and so the write() method considers the WCS to be linear. There are various possible solutions:
|
In GalSim, at the point where we will want to be writing this, we do know the size of the image to be written, so I can use your first solution. I tried it in our test suite, and it seems to work. Thanks. However, the TPV test still fails if I don't explicitly override the success=1 report from PyAst. So if you want to look into that as well, here is a corresponding script for that file that doesn't work:
My output from this script is:
The errors are quite a lot larger than the SIP errors we had been seeing, so it seems like the problem might be something else. I even put in the CRPIX values as well, since I thought they might be relevant. But it still failed. Similarly, using the original fc didn't work either. If you don't want to tackle this, I'm fine with leaving in the explicit override for TPV that I've had there to force it to use your native encoding rather than FITS-WCS. Here is the code snippet I use to do that:
Thanks. |
I investigated a bit more, and it looks like the ra,dec values for the TPV file come out reversed. Is there any reason that |
I think the issue here is that the WCS in tpv.fits has transposed axes. That is, the diagonal terms in the CD matrix are close to zero, and the off-diagonal elements predominate. In other words, even though CTYPE1 is "RA---TPV", in fact the first pixel axis is more closely aligned with Dec than RA. FITS WCS paper I implies this is bad form - from section 2.1.3 "Therefore, it is good form to transpose the header parameters along with the image so that the on-diagonal terms in the transformation matrix predominate." This is what AST is doing. If you look in the headers of test_tpv.fits you will see that CTYPE1 is "DEC--TPV". There are a couple of possible solutions:
|
I can do option 1 I guess. But it seems like the Perhaps at the very least, you could add a kwarg |
Don't forget an AST Frame represents an arbitrary coordinate system, which may not have any RA or Dec axes at all (e.g. the axes of a data value versus time plot for instance). AST is not just about 2-dimensional images of the sky, or even about FITS-WCS - it's a generic system for handling N-dimensional coordinate systems of many different types. So a "ra_dec=True" flag wouldn't really work since there may not be any ra or dec axes (or even any other form of celestial coords such as glon, glat, etc). It would be difficult (and I think unnecessarily restrictive) to mandate a fixed order for all possible combinations of all possible axis types (likewise, FITS-WCS does not mandate any particular order). However, if you want to write your code assuming that the WCS FrameSet has certain axes which are in a certain order, you can use the findframe method. For instance:
|
OK, that's fair. I'll add this |
Should that line cause a loss of precision? When I use it in the above script, the errors are ~0.02 arcsec, rather than <1.e-5 arcsec that was was getting before. This is on the original read, not the second one that you said should only be accurate to < 0.1 pixel.
which leads to
Since the original WCS was already using the FK5 system, I wouldn't have thought this would do anything to reduce the precision of the calculation. |
OK, for the purposes of our use in GalSim, I think I've settled on using the following code snippet when we use pyast to read in a WCS from a FITS file:
Then it will usually use the initial read result, which seems to be the most accurate if it works. But if that doesn't have RA, Dec for its axes (which I think the LonAxis test checks?), then we need to convert to something that does. Then afterward, I can just count on Does this seem right to you? |
Oh, and I should probably add that I've decided to leave in the overrides for the success=1 results for SIP, TPV, and ZPX. There are enough situations where registration errors of 0.1 pixels will be too large, so it seems safer to just stick with the pyast proprietary format rather than the lower precision fits encoding in these cases. (e.g. Weak lensing measurements with LSST require a registration accuracy of ~5mas, which is more like 0.02 pixels.) |
Regarding the larger errors when using findframe, I think it is due to the tpv.fits file using ICRS rather than FK5. The tpv.fits header includes: RADECSYS= 'ICRS ' / Astrometric system So the DS9 values (which BTW are produced by AST since DS9 uses AST) are ICRS but the values produced by the findframe FrameSet are FK5, which accounts for the errors. Changing the template supplied to findframe from FK5 to ICRS seems to fix the problem. Would fixing this issue tempt you to move from using lonaxis to using findframe? |
I'd rather just test whether the frame is some valid system -- ICRS or FK5 -- rather than force it into one or the other. Is there a better way to test whether the existing Frame is already a celestial system besides using LonAxis? |
Check if it's domain is "SKY" ? |
Nope. It's 'SKY' for the one that has the axes flipped as (Dec, RA). |
I've had a similar debate to this with respect to NDF sections in the Starlink software. I thought there was an open issue for it on the Starlink github repo but I can't find it now. I still think I agree with @rmjarvis that a 2-d SKY frame is a single entity that maps RA/Dec or Glong/Glat or whatever to something else. A user always expects RA to come first in the axis specification regardless of how that axis relates to the underlying pixel coordinates in the image. It's worse for NDF sections because the user does not have the ability to programmatically check lonaxis/lataxis. I think that compound frames, e.g. SKY-SPECTRUM or whatever, are a distraction because people aren't expecting SKY-SPECTRUM to act the same as SPECTRUM-SKY but they are expecting within SKY That longitude comes first. |
@rmjarvis The LonAxis test is as good as any other (if the frame is not a skyframe, an exception will be raised saying that he LonAxis attribute is undefined). But beware that you then can't assume anything about the specific coordinate system represented by your WCS FrameSet - it will represent whatever was in the FITS file, whether that be FK5, ICRS, galactic, ecliptic, or whatever. Checking that Domain is "SKY" does identify celestial systems, since (ra,dec) and (dec,ra) are both celestial systems, as are (glon,glat), (glat,glon), (elon,elat), etc. |
@timj A human putting together an NDF section specification is in the same situation as a bit of software - the first question to be asked is "what do the axes of this data file represent? RA/Dec/Glon/wavelength/MJD/focal planeX/Data value or what?". The answer to this question determines if you can use the file or not. But having answered that question, you will also now know the order of the axes. If I give you an image containing M57, and you want to display the centre of the galaxy, you get the (RA,Dec) of the centre from some catalogue, but before you can display it you need to check that the image I have given you has (RA,Dec) axes. If it instead has (glon,glat) axes for instance then you need to either convert the image to (RA,Dec) or convert your coordinates to galactic. So you run NDFTRACE or whatever to query the properties of the axes. But in so doing you also discover the order of the axes, and hence know how to construct the section specification. The notion that the axes of a Frame may be permuted into any convenient order is deeply embedded in the AST model, and has been in use a long time in a range of starlink software. Software that uses AST to do all it's WCS handling hardly ever needs to know the axis order - AST takes care of it. The places where you do need to know the axis order is when interacting with some external system, whether it be human or software. It's not unreasonable to expect there to be some interface layer that arbitrates between AST and the external system. After all, it's not only axis order that needs to be arbitrated, but also all the other properties of the coordinate system, like the specific coordinate system in use (FK5/ICRS, wavelength/frequency, UTC/TAI, etc). If you are going to mandate a specific axis order, then it would seem logical to mandate also all the other properties of the coordinate system, and say for instance that all sky positions must be given as ICRS (RA,Dec) - thus excluding ICRS (Dec,RA), FK5 (RA,Dec), (GLat,Glon), (ELon,ELat) etc. This is contrary to the way AST does things - AST aims to give you the freedom to express your coordinate system just how you want to. |
@timj If you had an image in which Dec was parallel to pixel axis 1 and RA was parallel to pixel axis 2 (i.e. north to the right and east upwards), would you still want the WCS axes specified in (Ra,Dec) order? I can see it would be advantageous in some circumstances, but on the other hand there could be other circumstances where people who would say that "axis 1" should be the Dec axis in such cases in order to give a clue that the image is rotated. FITS-WCS paper I follows this later approach in its recommendation that the CD or PC matrix should have its largest terms on the diagonal (i.e. each pixel axis should be associated with the WCS axis that is most nearly parallel to it). |
@rmjarvis There is another alternative to LonAxis that may appeal to you. If you use the findframe approach, but do not specify a system, then the system (i.e. FK5, ICRS, etc) will be left unchanged. So if you do:
then the only change that will be made to "wcs" is to flip the axis order to match that of a newly created SkyFrame (i.e. RA,Dec). All other properties of the coordinate system should remain unchanged. |
This works. I'll use that. Thanks!
Yes. Always. I don't see any problem with having a CD or PC matrix that is close to (0,1,1,0) or (0,1,-1,0) or (1,0,0,-1) or (0.6,0.8,-0.8,0.6) or any other rotation or flip. Alt-Az telescopes (LSST for instance) will frequently change between being near theta = 0 and theta = 90. Would you advocate changing the FITS WCS convention in the image files every time the rotator passes through 45 degrees? At the very least I always want my wcs software to return (ra,dec) when I ask it for the celestial position at some point in the image. But at least I now have a programmatic way to get PyAst to do that, so I'm fine with the |
Just to follow up on this. As far as I'm concerned, I'm happy with the resolution here, so this issue can probably be closed. Thanks for the help with that. I do think the user interface of the Or if you don't like that, it could be helpful to add something to the doc string to let people know about the option of using But if you don't want to do any of these, feel free to just close this issue and be done with it. These are just suggestions from the peanut gallery. :) |
Thanks for the suggestions. I'll probably go with your second option of adding further explanations to the docs. The issue with the first as I mentioned before is that it sort of assumes AST will only ever be used with plain (ra,dec) wcs. The input WCS could in principle represent almost anything - a (time,focal planeX,focal planeY) 3-D cube, or a 1-D spectrum for instance - so the principle is "when importing WCS into AST from some external source, always allow for the possibility that the WCS axes may not match the requirements of your application, in type or order". |
And my problem with the kwarg ra_dec that raises an exception is that it's a special case. In principle, if such an option existed, you should also have similar options for all other possible combination of axes. In fact I suppose the findframe approach is a generalised equivalent to what you suggest. |
I've added an example using findframe to the the pyast examples page at http://timj.github.io/starlink-pyast/node4.html (look for "Ensure that WCS Axes are in a Specified Order"). I've also added comments to the docs for the tran and findframe methods linked from http://timj.github.io/starlink-pyast/pyast.html. |
Good. Thanks for this. One slight typo I noticed:
Should be |
Fixed. Thanks for pointing it out. |
PyAst doesn't seem to be writing the information in SIP files correctly when writing them in FITS format. I believe it used to work correctly in a previous version of starlink-pyast, but I can't be 100% sure. I didn't try to go back to previous versions to try them out, so maybe I'm wrong and this was never working.
Anyway, here is a script that shows the problem:
The output I get from this is:
So the initial read works fine, but then writing to a file and reading it back in leads to an error of several arcsec. The problem is that none of the SIP information is getting output. It writes it as a simple TAN WCS, rather than TAN-SIP.
Am I doing something wrong with the I/O commands? Or is this a bug in PyAst?
Maybe just the return value from
fc2.write(wcs)
is wrong? It's possible that older versions reported this as 0, in which case the GalSim test suite would have skipped this check, since it would have been reported as not working. But now it claims success, so we check it.For what it's worth, I had noticed TPV and ZPX types being incorrectly reported as successfully written, and I had a workaround to explicitly countermand the success report in those cases. So maybe SIP is now also just wrongly reporting success here.
The text was updated successfully, but these errors were encountered: