File Coverage

blib/lib/Astro/FITS/HdrTrans/IRIS2.pm
Criterion Covered Total %
statement 21 194 10.8
branch 0 70 0.0
condition 0 42 0.0
subroutine 8 29 27.5
pod 21 22 95.4
total 50 357 14.0


line stmt bran cond sub pod time code
1             package Astro::FITS::HdrTrans::IRIS2;
2              
3             =head1 NAME
4              
5             Astro::FITS::HdrTrans::IRIS2 - IRIS-2 Header translations
6              
7             =head1 SYNOPSIS
8              
9             %generic_headers = translate_from_FITS(\%FITS_headers, \@header_array);
10              
11             %FITS_headers = transate_to_FITS(\%generic_headers, \@header_array);
12              
13             =head1 DESCRIPTION
14              
15             Converts information contained in AAO IRIS2 FITS headers to and from
16             generic headers. See Astro::FITS::HdrTrans for a list of generic
17             headers.
18              
19             =cut
20              
21 10     10   13905974 use 5.006;
  10         43  
22 10     10   54 use warnings;
  10         39  
  10         745  
23 10     10   60 use strict;
  10         19  
  10         237  
24 10     10   61 use Carp;
  10         21  
  10         966  
25              
26 10     10   781 use Math::Trig qw/ acos deg2rad rad2deg /;
  10         16510  
  10         740  
27              
28             # Inherit from Base
29 10     10   82 use base qw/ Astro::FITS::HdrTrans::Base /;
  10         29  
  10         1991  
30              
31 10     10   71 use vars qw/ $VERSION /;
  10         21  
  10         21553  
32              
33             # Note that we use %02 not %03 because of historical reasons
34             $VERSION = "1.64";
35              
36              
37             # for a constant mapping, there is no FITS header, just a generic
38             # header that is constant
39             my %CONST_MAP = (
40             COORDINATE_UNITS => 'degrees',
41             GAIN => 5.2,
42             NSCAN_POSITIONS => 1,
43             SCAN_INCREMENT => 1,
44             );
45              
46             # NULL mappings used to override base class implementations
47             my @NULL_MAP = ();
48              
49             # unit mapping implies that the value propogates directly
50             # to the output with only a keyword name change
51              
52             my %UNIT_MAP = (
53             DEC_BASE => "CRVAL2",
54             DEC_TELESCOPE_OFFSET => "TDECOFF",
55             DETECTOR_INDEX => "DINDEX",
56             DETECTOR_READ_TYPE => "METHOD",
57             DR_GROUP => "GRPNUM",
58             DR_RECIPE => "RECIPE",
59             EQUINOX => "EQUINOX",
60             EXPOSURE_TIME => "EXPOSED",
61             INSTRUMENT => "INSTRUME",
62             NUMBER_OF_EXPOSURES => "CYCLES",
63             NUMBER_OF_OFFSETS => "NOFFSETS",
64             NUMBER_OF_READS => "READS",
65             OBJECT => "OBJECT",
66             OBSERVATION_NUMBER => "RUN",
67             OBSERVATION_TYPE => "OBSTYPE",
68             RA_BASE => "CRVAL1",
69             RA_TELESCOPE_OFFSET => "TRAOFF",
70             SLIT_ANGLE => "TEL_PA",
71             SLIT_NAME => "SLIT",
72             SPEED_GAIN => "SPEED",
73             STANDARD => "STANDARD",
74             TELESCOPE => "TELESCOP",
75             WAVEPLATE_ANGLE => "WPLANGLE",
76             X_DIM => "NAXIS1",
77             X_LOWER_BOUND => "DETECXS",
78             X_OFFSET => "RAOFF",
79             X_REFERENCE_PIXEL => "CRPIX1",
80             X_UPPER_BOUND => "DETECXE",
81             Y_BASE => "DECBASE",
82             Y_DIM => "NAXIS2",
83             Y_LOWER_BOUND => "DETECYS",
84             Y_OFFSET => "DECOFF",
85             Y_REFERENCE_PIXEL => "CRPIX2",
86             Y_UPPER_BOUND => "DETECYE",
87             );
88              
89              
90             # Create the translation methods
91             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP, \@NULL_MAP );
92              
93              
94             =head1 METHODS
95              
96             =over 4
97              
98             =item B<this_instrument>
99              
100             The name of the instrument required to match (case insensitively)
101             against the INSTRUME/INSTRUMENT keyword to allow this class to
102             translate the specified headers. Called by the default
103             C<can_translate> method.
104              
105             $inst = $class->this_instrument();
106              
107             Returns "IRIS2".
108              
109             =cut
110              
111             sub this_instrument {
112 20     20 1 66 return "IRIS2";
113             }
114              
115             =back
116              
117             =head1 COMPLEX CONVERSIONS
118              
119             These methods are more complicated than a simple mapping. We have to
120             provide both from- and to-FITS conversions All these routines are
121             methods and the to_ routines all take a reference to a hash and return
122             the translated value (a many-to-one mapping) The from_ methods take a
123             reference to a generic hash and return a translated hash (sometimes
124             these are many-to-many)
125              
126             =over 4
127              
128             =item B<to_AIRMASS_END>
129              
130             Converts FITS header value of zenith distance into airmass value.
131              
132             =cut
133              
134             sub to_AIRMASS_END {
135 0     0 1   my $self = shift;
136 0           my $FITS_headers = shift;
137 0           my $pi = atan2( 1, 1 ) * 4;
138 0           my $return;
139 0 0         if (exists($FITS_headers->{ZDEND})) {
140 0           $return = 1 / cos( deg2rad($FITS_headers->{ZDEND}) );
141             }
142              
143 0           return $return;
144              
145             }
146              
147             =item B<from_AIRMASS_END>
148              
149             Converts airmass into zenith distance.
150              
151             =cut
152              
153             sub from_AIRMASS_END {
154 0     0 1   my $self = shift;
155 0           my $generic_headers = shift;
156 0           my %return_hash;
157 0 0         if (exists($generic_headers->{AIRMASS_END})) {
158 0           $return_hash{ZDEND} = rad2deg(acos($generic_headers->{AIRMASS_END}));
159             }
160 0           return %return_hash;
161             }
162              
163             =item B<to_AIRMASS_START>
164              
165             Converts FITS header value of zenith distance into airmass value.
166              
167             =cut
168              
169             sub to_AIRMASS_START {
170 0     0 1   my $self = shift;
171 0           my $FITS_headers = shift;
172 0           my $pi = atan2( 1, 1 ) * 4;
173 0           my $return;
174 0 0         if (exists($FITS_headers->{ZDSTART})) {
175 0           $return = 1 / cos( deg2rad($FITS_headers->{ZDSTART}) );
176             }
177              
178 0           return $return;
179              
180             }
181              
182             =item B<from_AIRMASS_START>
183              
184             Converts airmass into zenith distance.
185              
186             =cut
187              
188             sub from_AIRMASS_START {
189 0     0 1   my $self = shift;
190 0           my $generic_headers = shift;
191 0           my %return_hash;
192 0 0         if (exists($generic_headers->{AIRMASS_START})) {
193 0           $return_hash{ZDSTART} = rad2deg(acos($generic_headers->{AIRMASS_START}));
194             }
195 0           return %return_hash;
196             }
197              
198             =item B<to_COORDINATE_TYPE>
199              
200             Converts the C<EQUINOX> FITS header into B1950 or J2000, depending
201             on equinox value, and sets the C<COORDINATE_TYPE> generic header.
202              
203             =cut
204              
205             sub to_COORDINATE_TYPE {
206 0     0 1   my $self = shift;
207 0           my $FITS_headers = shift;
208 0           my $return;
209 0 0         if (exists($FITS_headers->{EQUINOX})) {
210 0 0         if ($FITS_headers->{EQUINOX} =~ /1950/) {
    0          
211 0           $return = "B1950";
212             } elsif ($FITS_headers->{EQUINOX} =~ /2000/) {
213 0           $return = "J2000";
214             }
215             }
216 0           return $return;
217             }
218              
219             =item B<to_DEC_SCALE>
220              
221             Calculate the Declination pixel scale from the CD matrix.
222              
223             =cut
224              
225             sub to_DEC_SCALE {
226 0     0 1   my $self = shift;
227 0           my $FITS_headers = shift;
228 0           my $cd11 = $FITS_headers->{CD1_1};
229 0           my $cd12 = $FITS_headers->{CD1_2};
230 0           my $cd21 = $FITS_headers->{CD2_1};
231 0           my $cd22 = $FITS_headers->{CD2_2};
232 0           my $sgn;
233 0 0         if ( ( $cd11 * $cd22 - $cd12 * $cd21 ) < 0 ) {
234 0           $sgn = -1;
235             } else {
236 0           $sgn = 1;
237             }
238 0           return abs( sqrt( $cd11**2 + $cd21**2 ) );
239             }
240              
241             =item B<to_FILTER>
242              
243             Determine the filter name. Depends on the value of IR2_FILT.
244              
245             =cut
246              
247             sub to_FILTER {
248 0     0 1   my $self = shift;
249 0           my $FITS_headers = shift;
250 0           my $return;
251              
252 0 0         if ( $FITS_headers->{IR2_FILT} =~ /^OPEN$/i ) {
253 0           $return = $FITS_headers->{IR2_COLD};
254             } else {
255 0           $return = $FITS_headers->{IR2_FILT};
256             }
257 0           $return =~ s/ //g;
258 0           return $return;
259             }
260              
261             =item B<to_GRATING_DISPERSION>
262              
263             Calculate grating dispersion.
264              
265             Dispersion is only a function of grism and blocking filter used, but
266             need to allow for various choices of blocking filter
267              
268             =cut
269              
270             sub to_GRATING_DISPERSION {
271 0     0 1   my $self = shift;
272 0           my $FITS_headers = shift;
273 0           my $return;
274              
275 0           my $obsmode = $self->to_OBSERVATION_MODE( $FITS_headers );
276 0           my $filter = $self->to_FILTER( $FITS_headers );
277              
278 0 0         if ( $obsmode eq 'spectroscopy' ) {
279 0 0 0       if ( uc($filter) eq 'K' || uc($filter) eq 'KS' ) {
    0 0        
    0 0        
    0 0        
280 0           $return = 0.0004423;
281             } elsif ( uc($filter) eq 'JS' ) {
282 0           $return = 0.0002322;
283             } elsif ( uc($filter) eq 'J' || uc($filter) eq 'JL' ) {
284 0           $return = 0.0002251;
285             } elsif ( uc($filter) eq 'H' || uc($filter) eq 'HS' || uc($filter) eq 'HL' ) {
286 0           $return = 0.0003413;
287             }
288             }
289 0           return $return;
290             }
291              
292             =item B<to_GRATING_DISPERSION>
293              
294             Calculate grating wavelength.
295              
296             Central wavelength is a function of grism + blocking filter + slit
297             used. Assume offset slit used for H/Hs and Jl, otherwise centre slit
298             is used. Central wavelengths computed for pixel 513, to match
299             calculation used in ORAC-DR.
300              
301             =cut
302              
303             sub to_GRATING_WAVELENGTH {
304 0     0 0   my $self = shift;
305 0           my $FITS_headers = shift;
306 0           my $return;
307              
308 0           my $obsmode = $self->to_OBSERVATION_MODE( $FITS_headers );
309 0           my $filter = $self->to_FILTER( $FITS_headers );
310              
311 0 0         if ( $obsmode eq 'spectroscopy' ) {
312 0 0 0       if ( uc( $filter ) eq 'K' || uc( $filter ) eq 'KS' ) {
    0 0        
    0 0        
    0 0        
313 0           $return = 2.249388;
314             } elsif ( uc($filter) eq 'JS' ) {
315 0           $return = 1.157610;
316             } elsif ( uc($filter) eq 'J' || uc($filter) eq 'JL' ) {
317 0           $return = 1.219538;
318             } elsif ( uc($filter) eq 'H' || uc($filter) eq 'HS' || uc($filter) eq 'HL' ) {
319 0           $return = 1.636566;
320             }
321             }
322 0           return $return;
323             }
324              
325             =item B<to_OBSERVATION_MODE>
326              
327             Determines the observation mode from the IR2_SLIT or IR2_GRSM FITS header values. If
328             IR2_SLIT value is equal to "OPEN1", then the observation mode is imaging.
329             Otherwise, the observation mode is spectroscopy. If IR2_GRSM is matches SAP or SIL then
330             it is spectroscopy. IR2_GRSM is used in preference to IR2_SLIT.
331              
332             =cut
333              
334             sub to_OBSERVATION_MODE {
335 0     0 1   my $self = shift;
336 0           my $FITS_headers = shift;
337 0           my $return;
338 0 0         if (exists($FITS_headers->{IR2_GRSM})) {
    0          
339 0 0         $return = ($FITS_headers->{IR2_GRSM} =~ /^(SAP|SIL)/i) ? "spectroscopy" : "imaging";
340             } elsif (exists($FITS_headers->{IR2_SLIT})) {
341 0 0         $return = ($FITS_headers->{IR2_SLIT} eq "OPEN1") ? "imaging" : "spectroscopy";
342             }
343 0           return $return;
344             }
345              
346             =item B<to_RA_SCALE>
347              
348             Calculate the right-ascension pixel scale from the CD matrix.
349              
350             =cut
351              
352             sub to_RA_SCALE {
353 0     0 1   my $self = shift;
354 0           my $FITS_headers = shift;
355 0           my $cd12 = $FITS_headers->{CD1_2};
356 0           my $cd22 = $FITS_headers->{CD2_2};
357 0           return sqrt( $cd12**2 + $cd22**2 );
358             }
359              
360             =item B<to_UTDATE>
361              
362             Converts FITS header values into standard UT date value of the form
363             YYYYMMDD.
364              
365             =cut
366              
367             sub to_UTDATE {
368 0     0 1   my $self = shift;
369 0           my $FITS_headers = shift;
370 0           my $return;
371 0 0         if (exists($FITS_headers->{UTDATE})) {
372 0           my $utdate = $FITS_headers->{UTDATE};
373 0           $utdate =~ s/://g;
374 0           $return = $utdate;
375             }
376              
377 0           return $return;
378             }
379              
380             =item B<from_UTDATE>
381              
382             Converts UT date in the form C<yyyymmdd> to C<yyyy:mm:dd>.
383              
384             =cut
385              
386             sub from_UTDATE {
387 0     0 1   my $self = shift;
388 0           my $generic_headers = shift;
389 0           my %return_hash;
390 0 0         if (exists($generic_headers->{UTDATE})) {
391 0           my $date = $generic_headers->{UTDATE};
392 0 0         return () unless defined $date;
393 0           $return_hash{UTDATE} = substr($date,0,4).":".
394             substr($date,4,2).":".substr($date,6,2);
395             }
396 0           return %return_hash;
397             }
398              
399             =item B<to_UTEND>
400              
401             Converts FITS header UT date/time values for the end of the observation into
402             a C<Time::Piece> object.
403              
404             =cut
405              
406             sub to_UTEND {
407 0     0 1   my $self = shift;
408 0           my $FITS_headers = shift;
409 0           my $return;
410 0 0 0       if (exists($FITS_headers->{UTDATE}) && exists($FITS_headers->{UTEND})) {
411 0           my $utdate = $FITS_headers->{UTDATE};
412 0           $utdate =~ s/:/-/g;
413 0           $return = $utdate . "T" . $FITS_headers->{UTEND};
414 0           $return = $self->_parse_iso_date( $return );
415             }
416 0           return $return;
417             }
418              
419             =item B<from_UTEND>
420              
421             Converts end date into two FITS headers for IRIS2: UTDATE
422             (in the format YYYYMMDD) and UTEND (HH:MM:SS).
423              
424             =cut
425              
426             sub from_UTEND {
427 0     0 1   my $self = shift;
428 0           my $generic_headers = shift;
429 0           my %return_hash;
430 0 0         if (exists($generic_headers->{UTEND})) {
431 0           my $date = $generic_headers->{UTEND};
432 0           $return_hash{UTDATE} = sprintf("%04d:%02d:%02d",
433             $date->year, $date->mon, $date->mday);
434 0           $return_hash{UTEND} = sprintf("%02d:%02d:%02d",
435             $date->hour, $date->minute, $date->second);
436             }
437 0           return %return_hash;
438             }
439              
440             =item B<to_UTSTART>
441              
442             Converts FITS header UT date/time values for the start of the observation
443             into a C<Time::Piece> object.
444              
445             =cut
446              
447             sub to_UTSTART {
448 0     0 1   my $self = shift;
449 0           my $FITS_headers = shift;
450 0           my $return;
451 0 0 0       if (exists($FITS_headers->{UTDATE}) && exists($FITS_headers->{UTSTART})) {
452 0           my $utdate = $FITS_headers->{UTDATE};
453 0           $utdate =~ s/:/-/g;
454 0           $return = $utdate . "T" . $FITS_headers->{UTSTART} . "";
455 0           $return = $self->_parse_iso_date( $return );
456             }
457 0           return $return;
458             }
459              
460             =item B<from_UTSTART>
461              
462             Converts the date into two FITS headers for IRIS2: UTDATE
463             (in the format YYYYMMDD) and UTSTART (HH:MM:SS).
464              
465             =cut
466              
467             sub from_UTSTART {
468 0     0 1   my $self = shift;
469 0           my $generic_headers = shift;
470 0           my %return_hash;
471 0 0         if (exists($generic_headers->{UTSTART})) {
472 0           my $date = $generic_headers->{UTSTART};
473 0           $return_hash{UTDATE} = sprintf("%04d:%02d:%02d",
474             $date->year, $date->mon, $date->mday);
475 0           $return_hash{UTSTART} = sprintf("%02d:%02d:%02d",
476             $date->hour, $date->minute, $date->second);
477             }
478 0           return %return_hash;
479             }
480              
481             =item B<to_X_BASE>
482              
483             Converts the decimal hours in the FITS header C<RABASE> into
484             decimal degrees for the generic header C<X_BASE>.
485              
486             =cut
487              
488             sub to_X_BASE {
489 0     0 1   my $self = shift;
490 0           my $FITS_headers = shift;
491 0           my $return;
492 0 0         if (exists($FITS_headers->{RABASE})) {
493 0           $return = $FITS_headers->{RABASE} * 15;
494             }
495 0           return $return;
496             }
497              
498             =item B<from_X_BASE>
499              
500             Converts the decimal degrees in the generic header C<X_BASE>
501             into decimal hours for the FITS header C<RABASE>.
502              
503             =cut
504              
505             sub from_X_BASE {
506 0     0 1   my $self = shift;
507 0           my $generic_headers = shift;
508 0           my %return_hash;
509 0 0         if (exists($generic_headers->{X_BASE})) {
510 0           $return_hash{'RABASE'} = $generic_headers->{X_BASE} / 15;
511             }
512 0           return %return_hash;
513             }
514              
515             =item B<to_X_SCALE>
516              
517             Converts a linear transformation matrix into a pixel scale in the right
518             ascension axis. Results are in arcseconds per pixel.
519              
520             =cut
521              
522             # X_SCALE conversion courtesy Micah Johnson, from the cdelrot.pl script
523             # supplied for use with XIMAGE.
524              
525             sub to_X_SCALE {
526 0     0 1   my $self = shift;
527 0           my $FITS_headers = shift;
528 0           my $return;
529 0 0 0       if (exists($FITS_headers->{CD1_2}) &&
530             exists($FITS_headers->{CD2_2}) ) {
531 0           my $cd12 = $FITS_headers->{CD1_2};
532 0           my $cd22 = $FITS_headers->{CD2_2};
533 0           $return = sqrt( $cd12**2 + $cd22**2 ) * 3600;
534             }
535 0           return $return;
536             }
537              
538             =item B<to_Y_SCALE>
539              
540             Converts a linear transformation matrix into a pixel scale in the declination
541             axis. Results are in arcseconds per pixel.
542              
543             =cut
544              
545             # Y_SCALE conversion courtesy Micah Johnson, from the cdelrot.pl script
546             # supplied for use with XIMAGE.
547              
548             sub to_Y_SCALE {
549 0     0 1   my $self = shift;
550 0           my $FITS_headers = shift;
551 0           my $return;
552 0 0 0       if (exists($FITS_headers->{CD1_1}) &&
      0        
      0        
553             exists($FITS_headers->{CD1_2}) &&
554             exists($FITS_headers->{CD2_1}) &&
555             exists($FITS_headers->{CD2_2}) ) {
556 0           my $cd11 = $FITS_headers->{CD1_1};
557 0           my $cd12 = $FITS_headers->{CD1_2};
558 0           my $cd21 = $FITS_headers->{CD2_1};
559 0           my $cd22 = $FITS_headers->{CD2_2};
560 0           my $sgn;
561 0 0         if ( ( $cd11 * $cd22 - $cd12 * $cd21 ) < 0 ) {
562 0           $sgn = -1;
563             } else {
564 0           $sgn = 1;
565             }
566 0           $return = $sgn * sqrt( $cd11**2 + $cd21**2 ) * 3600;
567             }
568 0           return $return;
569             }
570              
571             =back
572              
573             =head1 SEE ALSO
574              
575             C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::Base>.
576              
577             =head1 AUTHOR
578              
579             Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
580             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>
581              
582             =head1 COPYRIGHT
583              
584             Copyright (C) 2008 Science and Technology Facilities Council.
585             Copyright (C) 2002-2007 Particle Physics and Astronomy Research Council.
586             All Rights Reserved.
587              
588             This program is free software; you can redistribute it and/or modify it under
589             the terms of the GNU General Public License as published by the Free Software
590             Foundation; either version 2 of the License, or (at your option) any later
591             version.
592              
593             This program is distributed in the hope that it will be useful,but WITHOUT ANY
594             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
595             PARTICULAR PURPOSE. See the GNU General Public License for more details.
596              
597             You should have received a copy of the GNU General Public License along with
598             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
599             Place,Suite 330, Boston, MA 02111-1307, USA
600              
601             =cut
602              
603             1;