File Coverage

blib/lib/Astro/FITS/HdrTrans/FITS.pm
Criterion Covered Total %
statement 59 81 72.8
branch 11 40 27.5
condition 6 18 33.3
subroutine 12 12 100.0
pod 6 6 100.0
total 94 157 59.8


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Astro::FITS::HdrTrans::FITS - Standard FITS header translations
5              
6             =head1 SYNOPSIS
7              
8             use Astro::FITS::HdrTrans::FITS;
9              
10             %gen = Astro::FITS::HdrTrans::FITS->translate_from_FITS( %hdr );
11              
12             =head1 DESCRIPTION
13              
14             This class provides a generic set of translations that are specific
15             to the (few) headers that are commonly standardised across most
16             FITS files.
17              
18             Mainly deals with World Coordinate Systems and headers defined
19             in the FITS standards papers.
20              
21             =cut
22              
23             use 5.006;
24 48     48   26015127 use warnings;
  48         192  
25 48     48   234 use strict;
  48         142  
  48         1252  
26 48     48   199 use Carp;
  48         115  
  48         968  
27 48     48   231  
  48         122  
  48         3029  
28             use base qw/ Astro::FITS::HdrTrans::Base /;
29 48     48   249  
  48         108  
  48         20083  
30             use vars qw/ $VERSION /;
31 48     48   277  
  48         170  
  48         28473  
32             $VERSION = "1.65";
33              
34             # for a constant mapping, there is no FITS header, just a generic
35             # header that is constant
36             my %CONST_MAP = (
37             );
38              
39             # unit mapping implies that the value propogates directly
40             # to the output with only a keyword name change
41              
42             my %UNIT_MAP = (
43             DATA_UNITS => 'BUNIT',
44             DEC_SCALE => "CDELT2",
45             INSTRUMENT => 'INSTRUME',
46             RA_SCALE => "CDELT1",
47             TELESCOPE => 'TELESCOP',
48             X_BASE => "CRPIX1",
49             X_REFERENCE_PIXEL => "CRPIX1",
50             Y_BASE => "CRPIX2",
51             Y_REFERENCE_PIXEL => "CRPIX2",
52             );
53              
54              
55             # Create the translation methods
56             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP );
57              
58             =head1 COMPLEX CONVERSIONS
59              
60             These methods are more complicated than a simple mapping. We have to
61             provide both from- and to-FITS conversions All these routines are
62             methods and the to_ routines all take a reference to a hash and return
63             the translated value (a many-to-one mapping) The from_ methods take a
64             reference to a generic hash and return a translated hash (sometimes
65             these are many-to-many).
66              
67             =over 4
68              
69              
70             =item B<to_ROTATION>
71              
72             This determines the angle, in decimal degrees, of the declination or
73             latitude axis with respect to the second axis of the data array, measured
74             in the anticlockwise direction.
75              
76             It first looks for the linear-transformation CD matrix, widely used
77             including by IRAF and the precursor to the PC matrix. If this is
78             absent, the routine attempts to find the standard transformation
79             matrix PC defined in the FITS WCS Standard. Either matrix is
80             converted into a single rotation angle.
81              
82             In the absence of a PC matrix it looks for the CROTA2 keyword from the
83             AIPS convention.
84              
85             The evaluation from the CD matrix is based upon Micah Johnson's
86             cdelrot.pl script supplied for use with XIMAGE, extended to average
87             the two estimates using FITS-WCS Paper II Section 6.2 prescription.
88              
89             =cut
90              
91             my $self = shift;
92             my $FITS_headers = shift;
93 9     9 1 23 my $rotation;
94 9         17 my $rtod = 45 / atan2( 1, 1 );
95 9         17  
96 9         17 # Try the IRAF-style headers. Use the defaults prescribed in WCS Paper I,
97             # Section 2.1.2.
98             if ( defined( $FITS_headers->{CD1_1} ) || defined( $FITS_headers->{CD1_2} ) ||
99             defined( $FITS_headers->{CD2_1} ) || defined( $FITS_headers->{CD2_2} ) ) {
100 9 50 33     49 my $cd11 = defined( $FITS_headers->{CD1_1} ) ? $FITS_headers->{CD1_1} : 0.0;
    50 33        
    100 33        
      33        
      33        
      33        
101             my $cd21 = defined( $FITS_headers->{CD2_1} ) ? $FITS_headers->{CD2_1} : 0.0;
102 0 0       0 my $cd12 = defined( $FITS_headers->{CD1_2} ) ? $FITS_headers->{CD1_2} : 0.0;
103 0 0       0 my $cd22 = defined( $FITS_headers->{CD2_2} ) ? $FITS_headers->{CD2_2} : 0.0;
104 0 0       0  
105 0 0       0 # Determine the sense of the scales.
106             my $sgn1;
107             if ( $cd12 < 0 ) {
108 0         0 $sgn1 = -1;
109 0 0       0 } else {
110 0         0 $sgn1 = 1;
111             }
112 0         0  
113             my $sgn2;
114             if ( $cd21 < 0 ) {
115 0         0 $sgn2 = -1;
116 0 0       0 } else {
117 0         0 $sgn2 = 1;
118             }
119 0         0  
120             # Average the estimates of the rotation converting from radians to
121             # degrees (rtod).
122             $rotation = $rtod * 0.5 * ( atan2( $sgn1 * $cd21 / $rtod, $sgn1 * $cd11 / $rtod ) +
123             atan2( $sgn2 * $cd12 / $rtod, -$sgn2 * $cd22 / $rtod ) );
124 0         0  
125             # Now try the FITS WCS PC matrix. Use the defaults prescribed in WCS Paper I,
126             # Section 2.1.2.
127             } elsif ( defined( $FITS_headers->{PC1_1} ) || defined( $FITS_headers->{PC1_2} ) ||
128             defined( $FITS_headers->{PC2_1} ) || defined( $FITS_headers->{PC2_2} ) ) {
129             my $pc11 = defined( $FITS_headers->{PC1_1} ) ? $FITS_headers->{PC1_1} : 1.0;
130             my $pc21 = defined( $FITS_headers->{PC2_1} ) ? $FITS_headers->{PC2_1} : 0.0;
131 0 0       0 my $pc12 = defined( $FITS_headers->{PC1_2} ) ? $FITS_headers->{PC1_2} : 0.0;
132 0 0       0 my $pc22 = defined( $FITS_headers->{PC2_2} ) ? $FITS_headers->{PC2_2} : 1.0;
133 0 0       0  
134 0 0       0 # Average the estimates of the rotation converting from radians to
135             # degrees (rtod) as the matrix may not represent a pure rotation.
136             $rotation = $rtod * 0.5 * ( atan2( -$pc21 / $rtod, $pc11 / $rtod ) +
137             atan2( $pc12 / $rtod, $pc22 / $rtod ) );
138 0         0  
139             } elsif ( defined( $FITS_headers->{CROTA2} ) ) {
140             $rotation = $FITS_headers->{CROTA2};
141              
142 2         714 }
143             return $rotation;
144             }
145 9         2074  
146              
147             =item B<to_UTDATE>
148              
149             Converts the DATE-OBS keyword into a number of form YYYYMMDD.
150              
151             There is no corresponding C<from_UTDATE> method since there is
152             no corresponding FITS keyword.
153              
154             =cut
155              
156             my $class = shift;
157             my $FITS_headers = shift;
158             my $utstart = $class->to_UTSTART( $FITS_headers );
159 4     4 1 7 if (defined $utstart) {
160 4         4 return $utstart->strftime( '%Y%m%d' );
161 4         12 }
162 4 50       8 return;
163 4         11 }
164              
165 0         0  
166             =item B<to_UTEND>
167              
168             Converts UT date in C<DATE-END> header into C<Time::Piece> object.
169              
170             =cut
171              
172             my $class = shift;
173             my $FITS_headers = shift;
174             my $utend;
175             if ( exists( $FITS_headers->{'DATE-END'} ) ) {
176 6     6 1 12 $utend = $FITS_headers->{'DATE-END'};
177 6         194 } else {
178 6         10 # try subheaders
179 6 50       19 my @end = $class->via_subheader( $FITS_headers, "DATE-END" );
180 6         121 $utend = $end[-1];
181             }
182             my $return;
183 0         0 $return = $class->_parse_iso_date( $utend ) if defined $utend;
184 0         0 return $return;
185             }
186 6         310  
187 6 50       39 =item B<from_UTEND>
188 6         14  
189             Returns the ending observation time in FITS restricted ISO8601 format:
190             YYYY-MM-DDThh:mm:ss.
191              
192             =cut
193              
194             my $class = shift;
195             my $generic_headers = shift;
196             my %return_hash;
197             if ( exists( $generic_headers->{UTEND} ) ) {
198             my $date = $generic_headers->{UTEND};
199 8     8 1 24 $return_hash{'DATE-END'} = $date->datetime;
200 8         16 }
201 8         22 return %return_hash;
202 8 50       30 }
203 8         18  
204 8         52  
205             =item B<to_UTSTART>
206 8         433  
207             Converts UT date in C<DATE-OBS> header into date object.
208              
209             =cut
210              
211             my $class = shift;
212             my $FITS_headers = shift;
213              
214             my $utstart;
215             if ( exists( $FITS_headers->{'DATE-OBS'} ) ) {
216             $utstart = $FITS_headers->{"DATE-OBS"};
217 11     11 1 18 } else {
218 11         21 # try subheaders
219             $utstart = $class->via_subheader( $FITS_headers, "DATE-OBS" );
220 11         16 }
221 11 50       28 my $return;
222 11         206 $return = $class->_parse_iso_date( $utstart ) if defined $utstart;
223             return $return;
224             }
225 0         0  
226             =item B<from_UTSTART>
227 11         669  
228 11 50       51 Returns the starting observation time in FITS restricted ISO8601
229 11         40 format: YYYY-MM-DDThh:mm:ss.
230              
231             =cut
232              
233             my $class = shift;
234             my $generic_headers = shift;
235             my %return_hash;
236             if ( exists( $generic_headers->{UTSTART} ) ) {
237             my $date = $generic_headers->{UTSTART};
238             $return_hash{'DATE-OBS'} = $date->datetime;
239             }
240 8     8 1 22 return %return_hash;
241 8         15 }
242 8         15  
243 8 50       26 =back
244 8         14  
245 8         27 =head1 SEE ALSO
246              
247 8         208 C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::Base>.
248              
249             =head1 AUTHOR
250              
251             Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
252             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>.
253             Malcolm J. Currie E<lt>mjc@star.rl.ac.ukE<gt>
254              
255             =head1 COPYRIGHT
256              
257             Copyright (C) 2007-2008 Science and Technology Facilities Council.
258             Copyright (C) 2003-2007 Particle Physics and Astronomy Research Council.
259             All Rights Reserved.
260              
261             This program is free software; you can redistribute it and/or modify it under
262             the terms of the GNU General Public License as published by the Free Software
263             Foundation; either Version 2 of the License, or (at your option) any later
264             version.
265              
266             This program is distributed in the hope that it will be useful,but WITHOUT ANY
267             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
268             PARTICULAR PURPOSE. See the GNU General Public License for more details.
269              
270             You should have received a copy of the GNU General Public License along with
271             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
272             Place, Suite 330, Boston, MA 02111-1307, USA.
273              
274             =cut
275              
276             1;