[AstroPy] Question regarding WCS coordinates
Eric L. N. Jensen
ejensen1 at swarthmore.edu
Wed Jul 3 16:53:14 EDT 2013
I had to do something like this recently, converting images from a simulation into FITS files with WCS in the header so I could compare directly with ALMA data.
Below is the code I used - it's a little more complicated than your case since you aren't creating a FITS header from scratch, and maybe you don't need a third (velocity/frequency) dimension in your image, but hopefully it will give you an idea of how to proceed.
To give credit where it's due, this code derives largely from an IDL routine supplied by Kees Dullemond with his radmc3d code - I translated it to Python and modified it somewhat.
If you need more information about WCS keywords in the FITS standard, this paper is a good reference:
Pence et al. 2010 A&A 524, 40, http://www.aanda.org/articles/aa/full_html/2010/16/aa15362-10/aa15362-10.html
Hope this helps,
P.S. In the code below, the 'read image' routine returns a dictionary with various bits of information about the image, as well as the numpy array of the image itself - adapt as needed.
import numpy as np
from astropy.io import fits
cc = 2.9979245800000e10 # Light speed [cm/s]
pc = 3.08572e18 # Parsec [cm]
im = readimage(imagename)
pixdeg_x = 180.0*(im['sizepix_x']/(dpc*pc))/np.pi
pixdeg_y = 180.0*(im['sizepix_y']/(dpc*pc))/np.pi
freqhz = 1e4*cc/im['lambda']
image = im['image']
n_freq = len(freqhz)
# Because of the way that Python stores arrays, we need to swap around
# our data array before writing it, so that it is indexed in the order
# (freq, y, x), rather than (x, y, freq) - the last index in the Numpy
# array will become AXIS1 in the FITS image, and so on.
(nx, ny, nstokes, nfreq) = np.shape(image)
newimage = np.transpose(image, (3, 2, 1, 0))
(nx, ny, nfreq) = np.shape(image)
newimage = np.transpose(image, (2, 1, 0))
# Compute the conversion factor from erg/cm^2/s/Hz/ster to Jy/pixel
pixsurf_ster = pixdeg_x*pixdeg_y * (np.pi/180.)**2
factor = 1e+23 * pixsurf_ster
# And scale the image array accordingly:
image_in_jypix = factor * newimage
# Make FITS header information:
header = fits.Header()
header['BTYPE'] = 'Intensity'
header['BSCALE'] = 1
header['BZERO'] = 0
header['BUNIT'] = 'JY/PIXEL'
if radeg is not None:
header['EPOCH'] = 2000.
header['LONPOLE'] = 180.
header['CTYPE1'] = 'RA---SIN'
header['CRVAL1'] = radeg
# Figure out what units we are using per pixel:
unit = 'arcsec'
multiplier = 3600.
unit = 'mas'
multiplier = 3.6e6
unit = 'deg'
multiplier = 1
header['CDELT1'] = multiplier*pixdeg_x
header['CUNIT1'] = unit
# ...Zero point of coordinate system
header['CRPIX1'] = 1.0*((nx+1)/2)
if decdeg is not None:
header['CTYPE2'] = 'DEC--SIN'
header['CRVAL2'] = decdeg
header['CDELT2'] = multiplier*pixdeg_y
header['CUNIT2'] = unit
# ...Zero point of coordinate system
header['CRPIX2'] = 1.0* ((ny+1)/2)
# If the keyword is set for rest frequency, add that to the header as
# it gives a reference point for, e.g., the velocity of the frequency
# steps relative to some line rest frequency. Note that even though
# the keyword used here is 'restfreq', the FITS standard for this
# field is RESTFRQ, i.e. with no second 'E'.
if restfreq is not None:
header['RESTFRQ'] = (float(restfreq), 'Rest frequency of this transition')
# If they have specified a velocity offset, we shift all of the
# specified frequencies by that amount. This allows, e.g., mapping a
# transition of a particular CO line in radmc3d, but then accounting
# for the fact that a real object might have a center-of-mass radial
# velocity offset. Note that we do *not* shift the input 'restfreq'
# keyword, as that is presumed to be the real frequency of that
if vel_offset is not None:
# Assume input velocity is in km/s, so
# specify speed of light in those
c = 2.9979245800000e5 # Light speed [km/s]
freqhz *= (1. - vel_offset/c)
header['COMMENT'] = "Velocity offset of %0.2f km/s applied to model." % vel_offset
if n_freq > 1:
# multiple frequencies - set up the header keywords to define the
# third axis as frequency
header['CTYPE3'] = 'FREQ'
header['CUNIT3'] = 'Hz'
header['CRPIX3'] = 1.0
header['CRVAL3'] = freqhz
# Calculate the frequency step, assuming equal steps between all:
delta_freq = freqhz - freqhz
header['CDELT3'] = delta_freq
else: # only one frequency
header['RESTFREQ'] = freqhz
# Make a FITS file!
fits.writeto(fitsname, image_in_jypix, header, output_verify='fix')
On Jul 3, 2013, at 2:36 PM, John ZuHone wrote:
> Hi all,
> This question is probably more about WCS than it is about Astropy, but I intend to use Astropy to do it so I thought I would ask.
> I have some projected maps of gas temperature of a galaxy cluster that I made from FLASH simulation data using yt that I have put into FITS files. I also have some simulated Chandra event files made from the MARX Chandra simulator, of the same system.
> I would like to match the WCS coordinates of the two files. The simulated events file already has WCS coordinates in RA and DEC, and this is the coordinate system I would like to use for the temperature map. The information I have for the temperature map is the cell spacing in kpc, and the redshift of the simulated cluster, so with the chosen cosmology I also have the distance.
> How can I go about this? Sorry, I realize this is a bit involved (at least it seems that way to me).
> John ZuHone
> AstroPy mailing list
> AstroPy at scipy.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the AstroPy