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