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