WCS.jl Package Analysis

Why WCS.jl package

After the introduction of package FITSIO.jl for handling FITS files in Julia, another package was required to manage the World Coordinate System(WCS) transformations of a FITS object. The WCS info. is present in the header of one of the HDU(s) of a FITS file. These transformations map the pixel locations in an image to their real-world units, such as their position on the sky sphere. These transformations can work both forward (from pixel to sky) and backward (from sky to pixel). This package wraps the WCSLIB C library.

Installation

WCS.jl is a registered package in Julia and can be installed from package manager as: pkg> add WCS

or it can be build from source as: julia> Pkg.clone("https://github.com/JuliaAstro/WCS.jl")

Usage

After installing the package, you can start using it with julia> using WCS

Creating a WCS object

WCS objects are defined by a type WCSTransform which contains the following fields based on the information present in the header:

    flag::Cint
    naxis::Cint
    crpix::Ptr{Cdouble}
    pc::Ptr{Cdouble}
    cdelt::Ptr{Cdouble}
    crval::Ptr{Cdouble}
    cunit::Ptr{Cvoid}
    ctype::Ptr{Cvoid}
    lonpole::Cdouble
    latpole::Cdouble
    restfrq::Cdouble
    restwav::Cdouble
    npv::Cint
    npvmax::Cint
    pv::Ptr{PVCard}
    nps::Cint
    npsmax::Cint
    ps::Ptr{PSCard}
    cd::Ptr{Cdouble}
    crota::Ptr{Cdouble}
    altlin::Cint
    velref::Cint
    alt::NTuple{4, UInt8}
    colnum::Cint
    colax::Ptr{Cint}
    cname::Ptr{Cvoid}
    crder::Ptr{Cdouble}
    csyer::Ptr{Cdouble}
    czphs::Ptr{Cdouble}
    cperi::Ptr{Cdouble}
    wcsname::NTuple{72, UInt8}
    timesys::NTuple{72, UInt8}
    trefpos::NTuple{72, UInt8}
    trefdir::NTuple{72, UInt8}
    plephem::NTuple{72, UInt8}
    timeunit::NTuple{72, UInt8}
    dateref::NTuple{72, UInt8}
    mjdref::NTuple{2, Cdouble}
    timeoffs::Cdouble
    dateobs::NTuple{72, UInt8}
    datebeg::NTuple{72, UInt8}
    dateavg::NTuple{72, UInt8}
    dateend::NTuple{72, UInt8}
    mjdobs::Cdouble
    mjdbeg::Cdouble
    mjdavg::Cdouble
    mjdend::Cdouble
    jepoch::Cdouble
    bepoch::Cdouble
    tstart::Cdouble
    tstop::Cdouble
    xposure::Cdouble
    telapse::Cdouble
    timsyer::Cdouble
    timrder::Cdouble
    timedel::Cdouble
    timepixr::Cdouble
    obsgeo::NTuple{6, Cdouble}
    obsorbit::NTuple{72, UInt8}
    radesys::NTuple{72, UInt8}
    equinox::Cdouble
    specsys::NTuple{72, UInt8}
    ssysobs::NTuple{72, UInt8}
    velosys::Cdouble
    zsource::Cdouble
    ssyssrc::NTuple{72, UInt8}
    velangl::Cdouble
    ntab::Cint
    nwtb::Cint
    tab::Ptr{Cvoid}  # Ptr{tabprm}
    wtb::Ptr{Cvoid}  # Ptr{wtbarr}
    lngtyp::NTuple{8, UInt8}
    lattyp::NTuple{8, UInt8}
    lng::Cint
    lat::Cint
    spec::Cint
    cubeface::Cint
    types::Ptr{Cint}
    lin::linprm
    cel::celprm
    spc::spcprm
    err::Ptr{WCSErr}
    m_flag::Cint
    m_naxis::Cint
    m_crpix::Ptr{Cdouble}
    m_pc::Ptr{Cdouble}
    m_cdelt::Ptr{Cdouble}
    m_crval::Ptr{Cdouble}
    m_cunit::Ptr{Cvoid}
    m_ctype::Ptr{Cvoid}
    m_pv::Ptr{PVCard}
    m_ps::Ptr{PSCard}
    m_cd::Ptr{Cdouble}
    m_crota::Ptr{Cdouble}
    m_colax::Ptr{Cint}
    m_cname::Ptr{Cvoid}
    m_crder::Ptr{Cdouble}
    m_csyer::Ptr{Cdouble}
    m_czphs::Ptr{Cdouble}
    m_cperi::Ptr{Cdouble}
    m_tab::Ptr{Cvoid}  # Ptr{tabprm}
    m_wtb::Ptr{Cvoid}  # Ptr{wtbarr}

Creating from scratch

To create a WCSTransform from scratch, we can use the constructor like:

julia> wcs = WCSTransform(2;
                          cdelt = [-0.066667, 0.066667],
                          ctype = ["RA---AIR", "DEC--AIR"],
                          crpix = [-234.75, 8.3393],
                          crval = [0., -90],
                          pv    = [(2, 1, 45.0)])
WCSTransform(naxis=2)

where the first argument is the number of axes naxis and keyword arguments can also be passed to set various attributes of the transform. Specifying keyword arguments is equivalent to setting them after construction and the above is equivalent to:

julia> wcs = WCSTransform(2)
julia> wcs.cdelt = [-0.066667, 0.066667]
julia> wcs.ctype = ["RA---AIR", "DEC--AIR"]
julia> wcs.crpix = [1000., 1000.]
julia> wcs.crval = [0., -90]
julia> wcs.pv = [(2, 1, 45.0)]

Both will return a WCSTransform object.

Creating from a Header

Currently, we can use from_header(header) to convert the header which is in string format to a WCSTransform object. We can also pass a keyword argument relax which determines the treatment of non-standard keywords. The default is to accept all known non-standard keywords. Use relax=WCS.HDR_NONE to ignore all non-standard keywords. Use, e.g., relax=(WCS.HDR_RADECSYS & WCS.HDR_CROTAia) to only accept selected non-standard keywords.

There exisits a scope to make a WCSTransform object from a FITSHeader object and vice-versa.

Converting a WCSTransform back to Header

We can write a WCSTransform object back to a FITS header in form of a string by using to_header(wcs). The relax keyword can be used here too for controling how non-standard extensions to the WCS standard are handled.

Transformations

1) Pixel Coordinate to World Coordinate

Pixel Coordinate: Coordinates of each pixel in your N dimensional image. World Coordinate: Coordinates that serve to locate a measurement in some multidimensional parameter space. They include, for example, a measurable quantity such as the frequency or wavelength associated with each point in a spectrum or, more abstractly, the longitude and latitude in a conventional spherical coordinate system which define a direction in space.

Consider the above wcs object, the transformation can be done like:

julia> pixcoords = [0.0  24.0  45.0;  # x coordinates of a 3D image
                    0.0  38.0  98.0]  # y coordinates of a 3D image

julia> worldcoords = pix_to_world(wcs, pixcoords)
2x3 Array{Float64,2}:
 267.965   276.539   287.771 
 -73.7366  -71.9741  -69.6781

worldcoords represents the World Coordinates of the corresponding pixel coordinates specified according to the wcs data.

2) World Coordinate to Pixel Coordinate

We can simply use:

julia> pixcoords = world_to_pix(wcs, worldcoords)
2x3 Array{Float64,2}:
  1.16529e-12  24.0  45.0
 -7.10543e-14  38.0  98.0

pixcoords should be a 2-d array where pixcoords[:, i] is the i-th set of coordinates, or a 1-d array representing a single set of coordinates. worldcoords must be the same size and type as pixcoords.

Interacting with WCS Transform

To get the attributes of a WCSTransform object, we can use get_property(wcs, :attribute) as:

julia> getproperty(wcs, :cdelt)
2-element Array{Float64,1}:
 -0.066667
  0.066667

Similarly, to set some attribute of a WCSTransform object, we can use setproperty!(wcs, :attribute, value) as: julia> setproperty!(wcs, :cdelt, [-0.0003, 0.0002])

Other features

  • check what underlying C library version is being used.

    julia> WCS.wcslib_version()
    v"6.2.0"