=head1 NAME
Astro::FITS::HdrTrans::WFCAM - UKIRT WFCAM translations
=head1 SYNOPSIS
use Astro::FITS::HdrTrans::WFCAM;
%gen = Astro::FITS::HdrTrans::WFCAM->translate_from_FITS( %hdr );
=head1 DESCRIPTION
This class provides a generic set of translations that are specific to
the WFCAM camera of the United Kingdom Infrared Telescope.
=cut
use 5.006;
use strict;
use Carp;
# Inherit from UKIRTNew.
# We want the FITS standard versions of DATE-OBS/DATE-END parsing
# Not the UKIRT-specific versions that have Z problems.
use Astro::FITS::HdrTrans::FITS qw/ UTSTART UTEND /;
our $VERSION = "1.66";
# For a constant mapping, there is no FITS header, just a generic
# header that is constant.
my %CONST_MAP = (
POLARIMETRY => 0,
);
# NULL mappings used to override base class implementations
my @NULL_MAP = qw/ DETECTOR_INDEX WAVEPLATE_ANGLE /;
# Unit mapping implies that the value propogates directly
# to the output with only a keyword name change.
my %UNIT_MAP = (
# WFCAM specific
CAMERA_NUMBER => "CAMNUM",
DETECTOR_READ_TYPE => "READMODE",
NUMBER_OF_COADDS => "NEXP",
NUMBER_OF_JITTER_POSITIONS => "NJITTER",
NUMBER_OF_MICROSTEP_POSITIONS => "NUSTEP",
TILE_NUMBER => "TILENUM",
# CGS4 + MICHELLE + WFCAM
CONFIGURATION_INDEX => 'CNFINDEX',
);
# Create the translation methods.
__PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP, \@NULL_MAP );
=head1 METHODS
=over 4
=item B<this_instrument>
The name of the instrument required to match (case insensitively)
against the INSTRUME/INSTRUMENT keyword to allow this class to
translate the specified headers. Called by the default
C<can_translate> method.
$inst = $class->this_instrument();
Returns "WFCAM".
=cut
sub this_instrument {
return "WFCAM";
}
=back
=head1 COMPLEX CONVERSIONS
These methods are more complicated than a simple mapping. We have to
provide both from- and to-FITS conversions All these routines are
methods and the to_ routines all take a reference to a hash and return
the translated value (a many-to-one mapping). The from_ methods take
a reference to a generic hash and return a translated hash (sometimes
these are many-to-many).
=over 4
=item B<to_DATA_UNITS>
Returns the data units. This uses the C<BUNIT> header, with a default
of "counts/exp" (unless the observations was with a ND read type
between 2006-10-23 and 2006-12-20 when the default was "counts/sec").
=cut
sub to_DATA_UNITS {
my $self = shift;
my $FITS_headers = shift;
my $data_units = 'counts/exp';
if ( defined( $FITS_headers->{BUNIT} ) ) {
$data_units = $FITS_headers->{BUNIT};
} else {
my $date = $self->to_UTDATE( $FITS_headers );
if ( $date > 20061023 && $date < 20061220 ) {
my $read_type = $self->to_DETECTOR_READ_TYPE( $FITS_headers );
if ( substr( $read_type, 0, 2 ) eq 'ND' ) {
$data_units = 'counts/sec';
}
}
}
return $data_units;
}
=item B<to_DEC_SCALE>
Returns the declination pixel scale in in arcseconds per pixel. For
Cameras 1 and 3, it scales the C<CD2_1> keyword to the C<DEC_SCALE>
generic header. For Cameras 2 and 4, it scales the C<CD2_2> keyword
instead.
=cut
sub to_DEC_SCALE {
my $self = shift;
my $FITS_headers = shift;
my $scale;
my $camnum = $self->to_CAMERA_NUMBER( $FITS_headers );
if ( defined( $camnum ) ) {
if ( defined( $FITS_headers->{CD2_1} ) &&
defined( $FITS_headers->{CD1_2} ) &&
defined( $FITS_headers->{CD2_2} ) ) {
if ( $camnum == 1 ) {
$scale = $FITS_headers->{CD2_1} * 3600;
} elsif ( $camnum == 3 ) {
$scale = $FITS_headers->{CD2_1} * 3600;
} elsif ( $camnum == 2 || $camnum == 4 ) {
$scale = $FITS_headers->{CD2_2} * 3600;
}
}
}
return $scale;
}
=item B<from_DEC_SCALE>
For Cameras 1 and 3, it scales the C<DEC_SCALE> generic header to the
C<CD2_1> header. For Cameras 2 and 4, it scales C<DEC_SCALE> to the
C<CD2_2> header. The returned units are degrees per pixel.
=cut
sub from_DEC_SCALE {
my $self = shift;
my $generic_headers = shift;
my %return_hash;
my $dec_scale = $generic_headers->{'DEC_SCALE'};
my $camnum = $generic_headers->{'CAMERA_NUMBER'};
if ( defined( $dec_scale ) &&
defined( $camnum ) ) {
if ( $camnum == 1 || $camnum == 3 ) {
$return_hash{'CD2_1'} = $dec_scale / 3600;
} elsif ( $camnum == 2 || $camnum == 4 ) {
$return_hash{'CD2_2'} = $dec_scale / 3600;
}
}
return %return_hash;
}
=item B<to_GAIN>
Determines the gain entirely from camera number.
The GAIN FITS header is not used.
=cut
sub to_GAIN {
my $self = shift;
my $FITS_headers = shift;
my $gain;
if ( defined( $FITS_headers->{CAMNUM} ) ) {
my $camnum = $FITS_headers->{CAMNUM};
if ( $camnum == 1 || $camnum == 2 || $camnum == 3 ) {
$gain = 4.6;
} elsif ( $camnum == 4 ) {
$gain = 5.6;
} else {
$gain = 1.0;
}
} else {
$gain = 1.0;
}
return $gain;
}
=item B<from_GAIN>
This is a null operation. The C<GAIN> FITS header in WFCAM data is
always incorrect.
=cut
sub from_GAIN {
return ();
}
=item B<to_NUMBER_OF_OFFSETS>
Return the number of offsets (jitters and micro steps).
=cut
sub to_NUMBER_OF_OFFSETS {
my $self = shift;
my $FITS_headers = shift;
my $njitter = ( defined( $FITS_headers->{NJITTER} ) ? $FITS_headers->{NJITTER} : 1 );
my $nustep = ( defined( $FITS_headers->{NUSTEP} ) ? $FITS_headers->{NUSTEP} : 1 );
return $njitter * $nustep + 1;
}
=item B<to_RA_BASE>
Returns the C<RABASE> header converted to degrees.
=cut
sub to_RA_BASE {
my $self = shift;
my $FITS_headers = shift;
return ($FITS_headers->{RABASE} * 15.0);
}
=item B<to_RA_SCALE>
Returns the right-ascension pixel scale in arcseconds per pixel. For
Cameras 1 and 3, it scales the C<CD1_2> keyword to the C<RA_SCALE>
generic header. For Cameras 2 and 4, it scales the C<CD1_1> keyword
instead.
=cut
sub to_RA_SCALE {
my $self = shift;
my $FITS_headers = shift;
my $scale;
my $camnum = $self->to_CAMERA_NUMBER( $FITS_headers );
if ( defined( $camnum ) ) {
if ( defined( $FITS_headers->{CD1_1} ) &&
defined( $FITS_headers->{CD1_2} ) ) {
if ( $camnum == 1 || $camnum == 3 ) {
$scale = $FITS_headers->{CD1_2} * 3600;
} elsif ( $camnum == 2 || $camnum == 4 ) {
$scale = $FITS_headers->{CD1_1} * 3600;
}
}
}
return $scale;
}
=item B<from_RA_SCALE>
For Cameras 1 and 3, it scales the C<RA_SCALE> generic header to the
C<CD1_2> keyword. For Cameras 2 and 4, scales C<RA_SCALE> to the
C<CD1_1> keyword. Returned units are degrees per pixel.
=cut
sub from_RA_SCALE {
my $self = shift;
my $generic_headers = shift;
my %return_hash;
my $ra_scale = $generic_headers->{'RA_SCALE'};
my $camnum = $generic_headers->{'CAMERA_NUMBER'};
if ( defined( $ra_scale ) &&
defined( $camnum ) ) {
if ( $camnum == 1 || $camnum == 3 ) {
$return_hash{'CD1_2'} = $ra_scale / 3600;
} elsif ( $camnum == 2 || $camnum == 4 ) {
$return_hash{'CD1_1'} = $ra_scale / 3600;
}
}
return %return_hash;
}
=item B<to_ROTATION>
Determines the rotation of the array in world co-ordinates.
=cut
sub to_ROTATION {
my $self = shift;
my $FITS_headers = shift;
my $cd11 = $FITS_headers->{CD1_1};
my $cd12 = $FITS_headers->{CD1_2};
my $cd21 = $FITS_headers->{CD2_1};
my $cd22 = $FITS_headers->{CD2_2};
my $rad = 45 / atan2( 1, 1 );
my $rho_a = $rad * atan2( -$cd12 / $rad, $cd22 / $rad );
my $rho_b = $rad * atan2( $cd21 / $rad, $cd11 / $rad );
my $rotation = -0.5 * ( $rho_a + $rho_b );
return $rotation;
}
=back
=head1 SEE ALSO
C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::UKIRT>.
=head1 AUTHOR
Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>.
Malcolm J. Currie E<lt>mjc@jach.hawaii.eduE<gt>
=head1 COPYRIGHT
Copyright (C) 2008 Science and Technology Facilities Council.
Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either Version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful,but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307, USA.
=cut
1;