File Coverage

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