File Coverage

blib/lib/Astro/FITS/HdrTrans/WFCAM.pm
Criterion Covered Total %
statement 92 104 88.4
branch 16 46 34.7
condition 11 45 24.4
subroutine 18 18 100.0
pod 11 11 100.0
total 148 224 66.0


line stmt bran cond sub pod time code
1             package Astro::FITS::HdrTrans::WFCAM;
2              
3             =head1 NAME
4              
5             Astro::FITS::HdrTrans::WFCAM - UKIRT WFCAM translations
6              
7             =head1 SYNOPSIS
8              
9             use Astro::FITS::HdrTrans::WFCAM;
10              
11             %gen = Astro::FITS::HdrTrans::WFCAM->translate_from_FITS( %hdr );
12              
13             =head1 DESCRIPTION
14              
15             This class provides a generic set of translations that are specific to
16             the WFCAM camera of the United Kingdom Infrared Telescope.
17              
18             =cut
19              
20 10     10   30875265 use 5.006;
  10         50  
21 10     10   57 use warnings;
  10         23  
  10         364  
22 10     10   81 use strict;
  10         36  
  10         226  
23 10     10   48 use Carp;
  10         31  
  10         936  
24              
25             # Inherit from UKIRTNew.
26 10     10   78 use base qw/ Astro::FITS::HdrTrans::UKIRTNew /;
  10         20  
  10         1838  
27              
28             # We want the FITS standard versions of DATE-OBS/DATE-END parsing
29             # Not the UKIRT-specific versions that have Z problems.
30 10     10   73 use Astro::FITS::HdrTrans::FITS qw/ UTSTART UTEND /;
  10         20  
  10         149  
31              
32 10     10   68 use vars qw/ $VERSION /;
  10         20  
  10         9786  
33              
34             $VERSION = "1.64";
35              
36             # For a constant mapping, there is no FITS header, just a generic
37             # header that is constant.
38             my %CONST_MAP = (
39             POLARIMETRY => 0,
40             );
41              
42             # NULL mappings used to override base class implementations
43             my @NULL_MAP = qw/ DETECTOR_INDEX WAVEPLATE_ANGLE /;
44              
45             # Unit mapping implies that the value propogates directly
46             # to the output with only a keyword name change.
47              
48             my %UNIT_MAP = (
49             # WFCAM specific
50             CAMERA_NUMBER => "CAMNUM",
51             DETECTOR_READ_TYPE => "READMODE",
52             NUMBER_OF_COADDS => "NEXP",
53             NUMBER_OF_JITTER_POSITIONS => "NJITTER",
54             NUMBER_OF_MICROSTEP_POSITIONS => "NUSTEP",
55             TILE_NUMBER => "TILENUM",
56              
57             # CGS4 + MICHELLE + WFCAM
58             CONFIGURATION_INDEX => 'CNFINDEX',
59             );
60              
61              
62             # Create the translation methods.
63             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP, \@NULL_MAP );
64              
65             =head1 METHODS
66              
67             =over 4
68              
69             =item B<this_instrument>
70              
71             The name of the instrument required to match (case insensitively)
72             against the INSTRUME/INSTRUMENT keyword to allow this class to
73             translate the specified headers. Called by the default
74             C<can_translate> method.
75              
76             $inst = $class->this_instrument();
77              
78             Returns "WFCAM".
79              
80             =cut
81              
82             sub this_instrument {
83 20     20 1 61 return "WFCAM";
84             }
85              
86             =back
87              
88             =head1 COMPLEX CONVERSIONS
89              
90             These methods are more complicated than a simple mapping. We have to
91             provide both from- and to-FITS conversions All these routines are
92             methods and the to_ routines all take a reference to a hash and return
93             the translated value (a many-to-one mapping). The from_ methods take
94             a reference to a generic hash and return a translated hash (sometimes
95             these are many-to-many).
96              
97             =over 4
98              
99             =item B<to_DATA_UNITS>
100              
101             Returns the data units. This uses the C<BUNIT> header, with a default
102             of "counts/exp" (unless the observations was with a ND read type
103             between 2006-10-23 and 2006-12-20 when the default was "counts/sec").
104              
105             =cut
106              
107             sub to_DATA_UNITS {
108 1     1 1 5 my $self = shift;
109 1         5 my $FITS_headers = shift;
110 1         4 my $data_units = 'counts/exp';
111              
112 1 50       5 if ( defined( $FITS_headers->{BUNIT} ) ) {
113 0         0 $data_units = $FITS_headers->{BUNIT};
114             } else {
115 1         83 my $date = $self->to_UTDATE( $FITS_headers );
116              
117 1 50 33     12 if ( $date > 20061023 && $date < 20061220 ) {
118              
119 0         0 my $read_type = $self->to_DETECTOR_READ_TYPE( $FITS_headers );
120 0 0       0 if ( substr( $read_type, 0, 2 ) eq 'ND' ) {
121              
122 0         0 $data_units = 'counts/sec';
123             }
124             }
125             }
126              
127 1         6 return $data_units;
128              
129             }
130              
131             =item B<to_DEC_SCALE>
132              
133             Returns the declination pixel scale in in arcseconds per pixel. For
134             Cameras 1 and 3, it scales the C<CD2_1> keyword to the C<DEC_SCALE>
135             generic header. For Cameras 2 and 4, it scales the C<CD2_2> keyword
136             instead.
137              
138             =cut
139              
140             sub to_DEC_SCALE {
141 1     1 1 3 my $self = shift;
142 1         2 my $FITS_headers = shift;
143              
144 1         4 my $scale;
145 1         26 my $camnum = $self->to_CAMERA_NUMBER( $FITS_headers );
146 1 50       7 if ( defined( $camnum ) ) {
147 1 50 33     4 if ( defined( $FITS_headers->{CD2_1} ) &&
      33        
148             defined( $FITS_headers->{CD1_2} ) &&
149             defined( $FITS_headers->{CD2_2} ) ) {
150              
151 1 50 0     265 if ( $camnum == 1 ) {
    0          
    0          
152 1         5 $scale = $FITS_headers->{CD2_1} * 3600;
153             } elsif ( $camnum == 3 ) {
154 0         0 $scale = $FITS_headers->{CD2_1} * 3600;
155             } elsif ( $camnum == 2 || $camnum == 4 ) {
156 0         0 $scale = $FITS_headers->{CD2_2} * 3600;
157             }
158             }
159             }
160 1         72 return $scale;
161             }
162              
163             =item B<from_DEC_SCALE>
164              
165             For Cameras 1 and 3, it scales the C<DEC_SCALE> generic header to the
166             C<CD2_1> header. For Cameras 2 and 4, it scales C<DEC_SCALE> to the
167             C<CD2_2> header. The returned units are degrees per pixel.
168              
169             =cut
170              
171             sub from_DEC_SCALE {
172 1     1 1 3 my $self = shift;
173 1         3 my $generic_headers = shift;
174              
175 1         2 my %return_hash;
176              
177 1         4 my $dec_scale = $generic_headers->{'DEC_SCALE'};
178 1         2 my $camnum = $generic_headers->{'CAMERA_NUMBER'};
179              
180 1 50 33     8 if ( defined( $dec_scale ) &&
181             defined( $camnum ) ) {
182              
183 1 50 33     8 if ( $camnum == 1 || $camnum == 3 ) {
    0 0        
184 1         6 $return_hash{'CD2_1'} = $dec_scale / 3600;
185             } elsif ( $camnum == 2 || $camnum == 4 ) {
186 0         0 $return_hash{'CD2_2'} = $dec_scale / 3600;
187             }
188             }
189              
190 1         8 return %return_hash;
191             }
192              
193             =item B<to_GAIN>
194              
195             Determines the gain entirely from camera number.
196              
197             The GAIN FITS header is not used.
198              
199             =cut
200              
201             sub to_GAIN {
202 1     1 1 3 my $self = shift;
203 1         3 my $FITS_headers = shift;
204 1         3 my $gain;
205 1 50       5 if ( defined( $FITS_headers->{CAMNUM} ) ) {
206 1         70 my $camnum = $FITS_headers->{CAMNUM};
207 1 50 33     87 if ( $camnum == 1 || $camnum == 2 || $camnum == 3 ) {
    0 33        
208 1         5 $gain = 4.6;
209             } elsif ( $camnum == 4 ) {
210 0         0 $gain = 5.6;
211             } else {
212 0         0 $gain = 1.0;
213             }
214             } else {
215 0         0 $gain = 1.0;
216             }
217 1         4 return $gain;
218             }
219              
220             =item B<from_GAIN>
221              
222             This is a null operation. The C<GAIN> FITS header in WFCAM data is
223             always incorrect.
224              
225             =cut
226              
227             sub from_GAIN {
228 1     1 1 8 return ();
229             }
230              
231             =item B<to_NUMBER_OF_OFFSETS>
232              
233             Return the number of offsets (jitters and micro steps).
234              
235             =cut
236              
237             sub to_NUMBER_OF_OFFSETS {
238 1     1 1 6 my $self = shift;
239 1         3 my $FITS_headers = shift;
240 1 50       4 my $njitter = ( defined( $FITS_headers->{NJITTER} ) ? $FITS_headers->{NJITTER} : 1 );
241 1 50       134 my $nustep = ( defined( $FITS_headers->{NUSTEP} ) ? $FITS_headers->{NUSTEP} : 1 );
242              
243 1         131 return $njitter * $nustep + 1;
244              
245             }
246              
247             =item B<to_RA_BASE>
248              
249             Returns the C<RABASE> header converted to degrees.
250              
251             =cut
252              
253             sub to_RA_BASE {
254 1     1 1 5 my $self = shift;
255 1         4 my $FITS_headers = shift;
256 1         4 return ($FITS_headers->{RABASE} * 15.0);
257             }
258              
259             =item B<to_RA_SCALE>
260              
261             Returns the right-ascension pixel scale in arcseconds per pixel. For
262             Cameras 1 and 3, it scales the C<CD1_2> keyword to the C<RA_SCALE>
263             generic header. For Cameras 2 and 4, it scales the C<CD1_1> keyword
264             instead.
265              
266             =cut
267              
268             sub to_RA_SCALE {
269 1     1 1 27 my $self = shift;
270 1         5 my $FITS_headers = shift;
271              
272 1         4 my $scale;
273 1         33 my $camnum = $self->to_CAMERA_NUMBER( $FITS_headers );
274 1 50       7 if ( defined( $camnum ) ) {
275 1 50 33     5 if ( defined( $FITS_headers->{CD1_1} ) &&
276             defined( $FITS_headers->{CD1_2} ) ) {
277              
278 1 50 33     143 if ( $camnum == 1 || $camnum == 3 ) {
    0 0        
279 1         4 $scale = $FITS_headers->{CD1_2} * 3600;
280             } elsif ( $camnum == 2 || $camnum == 4 ) {
281 0         0 $scale = $FITS_headers->{CD1_1} * 3600;
282             }
283             }
284             }
285 1         86 return $scale;
286             }
287              
288             =item B<from_RA_SCALE>
289              
290             For Cameras 1 and 3, it scales the C<RA_SCALE> generic header to the
291             C<CD1_2> keyword. For Cameras 2 and 4, scales C<RA_SCALE> to the
292             C<CD1_1> keyword. Returned units are degrees per pixel.
293              
294             =cut
295              
296             sub from_RA_SCALE {
297 1     1 1 3 my $self = shift;
298 1         2 my $generic_headers = shift;
299              
300 1         3 my %return_hash;
301              
302 1         3 my $ra_scale = $generic_headers->{'RA_SCALE'};
303 1         3 my $camnum = $generic_headers->{'CAMERA_NUMBER'};
304              
305 1 50 33     9 if ( defined( $ra_scale ) &&
306             defined( $camnum ) ) {
307              
308 1 50 33     6 if ( $camnum == 1 || $camnum == 3 ) {
    0 0        
309 1         7 $return_hash{'CD1_2'} = $ra_scale / 3600;
310             } elsif ( $camnum == 2 || $camnum == 4 ) {
311 0         0 $return_hash{'CD1_1'} = $ra_scale / 3600;
312             }
313             }
314              
315 1         14 return %return_hash;
316             }
317              
318             =item B<to_ROTATION>
319              
320             Determines the rotation of the array in world co-ordinates.
321              
322             =cut
323              
324             sub to_ROTATION {
325 1     1 1 3 my $self = shift;
326 1         4 my $FITS_headers = shift;
327 1         4 my $cd11 = $FITS_headers->{CD1_1};
328 1         68 my $cd12 = $FITS_headers->{CD1_2};
329 1         65 my $cd21 = $FITS_headers->{CD2_1};
330 1         670 my $cd22 = $FITS_headers->{CD2_2};
331              
332 1         79 my $rad = 45 / atan2( 1, 1 );
333              
334 1         13 my $rho_a = $rad * atan2( -$cd12 / $rad, $cd22 / $rad );
335 1         4 my $rho_b = $rad * atan2( $cd21 / $rad, $cd11 / $rad );
336 1         3 my $rotation = -0.5 * ( $rho_a + $rho_b );
337              
338 1         4 return $rotation;
339             }
340              
341             =back
342              
343             =head1 SEE ALSO
344              
345             C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::UKIRT>.
346              
347             =head1 AUTHOR
348              
349             Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
350             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>.
351             Malcolm J. Currie E<lt>mjc@jach.hawaii.eduE<gt>
352              
353             =head1 COPYRIGHT
354              
355             Copyright (C) 2008 Science and Technology Facilities Council.
356             Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
357             All Rights Reserved.
358              
359             This program is free software; you can redistribute it and/or modify it under
360             the terms of the GNU General Public License as published by the Free Software
361             Foundation; either Version 2 of the License, or (at your option) any later
362             version.
363              
364             This program is distributed in the hope that it will be useful,but WITHOUT ANY
365             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
366             PARTICULAR PURPOSE. See the GNU General Public License for more details.
367              
368             You should have received a copy of the GNU General Public License along with
369             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
370             Place, Suite 330, Boston, MA 02111-1307, USA.
371              
372             =cut
373              
374             1;