File Coverage

blib/lib/Astro/FITS/HdrTrans/WFCAM.pm
Criterion Covered Total %
statement 89 101 88.1
branch 16 46 34.7
condition 11 45 24.4
subroutine 17 17 100.0
pod 11 11 100.0
total 144 220 65.4


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