File Coverage

blib/lib/Astro/FITS/HdrTrans/FITS.pm
Criterion Covered Total %
statement 56 78 71.7
branch 11 40 27.5
condition 6 18 33.3
subroutine 11 11 100.0
pod 6 6 100.0
total 90 153 58.8


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