File Coverage

blib/lib/Astro/FITS/HdrTrans/INGRID.pm
Criterion Covered Total %
statement 18 216 8.3
branch 0 54 0.0
condition 0 27 0.0
subroutine 7 37 18.9
pod 30 31 96.7
total 55 365 15.0


line stmt bran cond sub pod time code
1             package Astro::FITS::HdrTrans::INGRID;
2              
3             =head1 NAME
4              
5             Astro::FITS::HdrTrans::INGRID - WHT INGRID translations
6              
7             =head1 SYNOPSIS
8              
9             use Astro::FITS::HdrTrans::INGRID;
10              
11             %gen = Astro::FITS::HdrTrans::INGRID->translate_from_FITS( %hdr );
12              
13             =head1 DESCRIPTION
14              
15             This class provides a generic set of translations that are specific to
16             the INGRID camera of the William Herschel Telescope.
17              
18             =cut
19              
20 10     10   11311912 use 5.006;
  10         60  
21 10     10   62 use warnings;
  10         35  
  10         461  
22 10     10   60 use strict;
  10         40  
  10         275  
23 10     10   51 use Carp;
  10         29  
  10         981  
24              
25             # Inherit from FITS.
26 10     10   65 use base qw/ Astro::FITS::HdrTrans::FITS /;
  10         20  
  10         2109  
27              
28 10     10   68 use vars qw/ $VERSION /;
  10         33  
  10         25562  
29              
30             $VERSION = "1.63";
31              
32             # For a constant mapping, there is no FITS header, just a generic
33             # header that is constant.
34             my %CONST_MAP = (
35             POLARIMETRY => 0,
36             OBSERVATION_MODE => 'imaging',
37             WAVEPLATE_ANGLE => 0,
38             );
39              
40             # NULL mappings used to override base-class implementations.
41             my @NULL_MAP = qw/ /;
42              
43             # Unit mapping implies that the value propogates directly
44             # to the output with only a keyword name change.
45              
46             my %UNIT_MAP = (
47             AIRMASS_END => "AIRMASS",
48             AIRMASS_START => "AIRMASS",
49             EXPOSURE_TIME => "EXPTIME",
50             FILTER => "INGF1NAM",
51             INSTRUMENT => "DETECTOR",
52             NUMBER_OF_EXPOSURES => "COAVERAG",
53             NUMBER_OF_READS => "NUMREADS",
54             OBSERVATION_NUMBER => "RUN"
55             );
56              
57              
58             # Create the translation methods.
59             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP, \@NULL_MAP );
60              
61             =head1 METHODS
62              
63             =over 4
64              
65             =item B<this_instrument>
66              
67             The name of the instrument required to match (case insensitively)
68             against the INSTRUME/INSTRUMENT keyword to allow this class to
69             translate the specified headers. Called by the default
70             C<can_translate> method.
71              
72             $inst = $class->this_instrument();
73              
74             Returns "INGRID".
75              
76             =cut
77              
78             sub this_instrument {
79 20     20 1 94 return qr/^INGRID/;
80             }
81              
82             =back
83              
84             =head1 COMPLEX CONVERSIONS
85              
86             =over 4
87              
88             =item B<to_DEC_BASE>
89              
90             Converts the base declination from sexagesimal d:m:s to decimal
91             degrees using the C<CAT-DEC> keyword, defaulting to 0.0.
92              
93             =cut
94              
95             sub to_DEC_BASE {
96 0     0 1   my $self = shift;
97 0           my $FITS_headers = shift;
98 0           my $dec = 0.0;
99 0           my $sexa = $FITS_headers->{"CAT-DEC"};
100 0 0         if ( defined( $sexa ) ) {
101 0           $dec = $self->dms_to_degrees( $sexa );
102             }
103 0           return $dec;
104             }
105              
106             =item B<to_DEC_SCALE>
107              
108             Sets the declination scale in arcseconds per pixel. The C<CCDYPIXE>
109             and C<INGPSCAL> headers are used when both are defined. Otherwise it
110             returns a default value of 0.2387 arcsec/pixel, assuming north is up.
111              
112             =cut
113              
114             sub to_DEC_SCALE {
115 0     0 1   my $self = shift;
116 0           my $FITS_headers = shift;
117 0           my $decscale = 0.2387;
118              
119             # Assumes either x-y scales the same or the y corresponds to
120             # declination.
121 0           my $ccdypixe = $self->via_subheader( $FITS_headers, "CCDYPIXE" );
122 0           my $ingpscal = $self->via_subheader( $FITS_headers, "INGPSCAL" );
123 0 0 0       if ( defined $ccdypixe && defined $ingpscal ) {
124 0           $decscale = $ccdypixe * 1000.0 * $ingpscal;
125             }
126 0           return $decscale;
127             }
128              
129             =item B<to_DEC_TELESCOPE_OFFSET>
130              
131             Sets the declination telescope offset in arcseconds. It uses the
132             C<CAT-DEC> and C<DEC> keywords to derive the offset, and if either
133             does not exist, it returns a default of 0.0.
134              
135             =cut
136              
137             sub to_DEC_TELESCOPE_OFFSET {
138 0     0 1   my $self = shift;
139 0           my $FITS_headers = shift;
140 0           my $decoffset = 0.0;
141 0 0 0       if ( exists $FITS_headers->{"CAT-DEC"} && exists $FITS_headers->{DEC} ) {
142              
143             # Obtain the reference and telescope declinations positions measured in degrees.
144 0           my $refdec = $self->dms_to_degrees( $FITS_headers->{"CAT-DEC"} );
145 0           my $dec = $self->dms_to_degrees( $FITS_headers->{DEC} );
146              
147             # Find the offsets between the positions in arcseconds on the sky.
148 0           $decoffset = 3600.0 * ( $dec - $refdec );
149             }
150              
151             # The sense is reversed compared with UKIRT, as these measure the
152             # place son the sky, not the motion of the telescope.
153 0           return -1.0 * $decoffset
154             }
155              
156             =item B<to_DETECTOR_READ_TYPE>
157              
158             Returns the UKIRT-like detector type "STARE" or "NDSTARE" from the
159             FITS C<REDMODE> and C<NUMREADS> keywords.
160              
161             This is guesswork at present.
162              
163             =cut
164              
165             sub to_DETECTOR_READ_TYPE {
166 0     0 1   my $self = shift;
167 0           my $FITS_headers = shift;
168 0           my $read_type;
169 0           my $readout_mode = $FITS_headers->{READMODE};
170 0           my $nreads = $FITS_headers->{NUMREADS};
171 0 0 0       if ( $readout_mode =~ /^mndr/i ||
    0 0        
172             ( $readout_mode =~ /^cds/i && $nreads == 1 ) ) {
173 0           $read_type = "STARE";
174             } elsif ( $readout_mode =~ /^cds/i ) {
175 0           $read_type = "NDSTARE";
176             }
177 0           return $read_type;
178             }
179              
180             =item B<to_DR_RECIPE>
181              
182             Returns the data-reduction recipe name. The selection depends on the
183             values of the C<OBJECT> and C<OBSTYPE> keywords. The default is
184             "QUICK_LOOK". A dark returns "REDUCE_DARK", and an object's recipe is
185             "JITTER_SELF_FLAT".
186              
187             =cut
188              
189             # No clue what the recipe is apart for a dark and assume a dither
190             # pattern means JITTER_SELF_FLAT.
191             sub to_DR_RECIPE {
192 0     0 1   my $self = shift;
193 0           my $FITS_headers = shift;
194 0           my $recipe = "QUICK_LOOK";
195              
196             # Look for a dither pattern. These begin D-<n>/<m>: where
197             # <m> represents the number of jitter positions in the group
198             # and <n> is the number within the group.
199 0           my $object = $FITS_headers->{OBJECT};
200 0 0         if ( $object =~ /D-\d+\/\d+/ ) {
    0          
201 0           $recipe = "JITTER_SELF_FLAT";
202             } elsif ( $FITS_headers->{OBSTYPE} =~ /DARK/i ) {
203 0           $recipe = "REDUCE_DARK";
204             }
205              
206 0           return $recipe;
207             }
208              
209             =item B<to_EQUINOX>
210              
211             Returns the equinox in decimal years. It's taken from the C<CAT-EQUI>
212             keyword, if it exists, defaulting to 2000.0 otherwise.
213              
214             =cut
215              
216             sub to_EQUINOX {
217 0     0 1   my $self = shift;
218 0           my $FITS_headers = shift;
219 0           my $equinox = 2000.0;
220 0 0         if ( exists $FITS_headers->{"CAT-EQUI"} ) {
221 0           $equinox = $FITS_headers->{"CAT-EQUI"};
222 0           $equinox =~ s/[BJ]//;
223             }
224 0           return $equinox;
225             }
226              
227             =item B<to_GAIN>
228              
229             Returns the gain in electrons per data number. This is taken from
230             the C<GAIN> keyword, with a default of 4.1.
231              
232             =cut
233              
234             sub to_GAIN {
235 0     0 1   my $self = shift;
236 0           my $FITS_headers = shift;
237 0           my $gain = 4.1;
238 0           my $subval = $self->via_subheader( $FITS_headers, "GAIN" );
239 0 0         $gain = $subval if defined $subval;
240 0           return $gain;
241             }
242              
243             =item B<to_NUMBER_OF_OFFSETS>
244              
245             Returns the number of offsets. It uses the UKIRT convention so
246             it is equivalent to the number of dither positions plus one.
247             The value is derived from the C<OBJECT> keyword, with a default of 6.
248              
249             =cut
250              
251             sub to_NUMBER_OF_OFFSETS {
252 0     0 1   my $self = shift;
253 0           my $FITS_headers = shift;
254 0           my $noffsets = 5;
255              
256             # Look for a dither pattern. These begin D-<n>/<m>: where
257             # <m> represents the number of jitter positions in the group
258             # and <n> is the number within the group.
259 0           my $object = $FITS_headers->{OBJECT};
260 0 0         if ( $object =~ /D-\d+\/\d+/ ) {
261              
262             # Extract the string between the solidus and the colon. Add one
263             # to match the UKIRT convention.
264 0           $noffsets = substr( $object, index( $object, "/" ) + 1 );
265 0           $noffsets = substr( $noffsets, 0, index( $noffsets, ":" ) );
266             }
267 0           return $noffsets + 1;
268             }
269              
270             =item B<to_OBJECT>
271              
272             Reeturns the object name. It is extracted from the C<OBJECT> keyword.
273              
274             =cut
275              
276             sub to_OBJECT {
277 0     0 1   my $self = shift;
278 0           my $FITS_headers = shift;
279 0           my $object = $FITS_headers->{OBJECT};
280              
281             # Look for a dither pattern. These begin D-<n>/<m>: where
282             # <m> represents the number of jitter positions in the group
283             # and <n> is the number within the group. We want to extract
284             # the actual object name.
285 0 0         if ( $object =~ /D-\d+\/\d+/ ) {
286 0           $object = substr( $object, index( $object, ":" ) + 2 );
287             }
288 0           return $object;
289             }
290              
291             =item B<to_OBSERVATION_TYPE>
292              
293             Determines the observation type from the C<OBSTYPE> keyword provided it is
294             "TARGET" for an object dark frame.
295              
296             =cut
297              
298             sub to_OBSERVATION_TYPE {
299 0     0 1   my $self = shift;
300 0           my $FITS_headers = shift;
301 0           my $obstype = uc( $FITS_headers->{OBSTYPE} );
302 0 0         if ( $obstype eq "TARGET" ) {
303 0           $obstype = "OBJECT";
304             }
305 0           return $obstype;
306             }
307              
308             =item B<to_RA_BASE>
309              
310             Converts the base right ascension from sexagesimal h:m:s to decimal degrees
311             using the C<CAT-RA> keyword, defaulting to 0.0.
312              
313             =cut
314              
315             sub to_RA_BASE {
316 0     0 1   my $self = shift;
317 0           my $FITS_headers = shift;
318 0           my $ra = 0.0;
319 0           my $sexa = $FITS_headers->{"CAT-RA"};
320 0 0         if ( defined( $sexa ) ) {
321 0           $ra = $self->hms_to_degrees( $sexa );
322             }
323 0           return $ra;
324             }
325              
326             =item B<to_RA_SCALE>
327              
328             Sets the right-ascension scale in arcseconds per pixel. The C<CCDXPIXE>
329             and C<INGPSCAL> headers are used when both are defined. Otherwise it
330             returns a default value of 0.2387 arcsec/pixel, assuming east is to
331             the left.
332              
333             =cut
334              
335             sub to_RA_SCALE {
336 0     0 1   my $self = shift;
337 0           my $FITS_headers = shift;
338 0           my $rascale = -0.2387;
339              
340             # Assumes either x-y scales the same or the x corresponds to right
341             # ascension, and right ascension decrements with increasing x.
342 0           my $ccdxpixe = $self->via_subheader( $FITS_headers, "CCDXPIXE" );
343 0           my $ingpscal = $self->via_subheader( $FITS_headers, "INGPSCAL" );
344 0 0 0       if ( defined $ccdxpixe && defined $ingpscal ) {
345 0           $rascale = $ccdxpixe * -1000.0 * $ingpscal;
346             }
347 0           return $rascale;
348             }
349              
350             =item B<to_RA_TELESCOPE_OFFSET>
351              
352             Sets the right-ascension telescope offset in arcseconds. It uses the
353             C<CAT-RA>, C<RA>, C<CAT-DEC> keywords to derive the offset, and if any
354             of these keywords does not exist, it returns a default of 0.0.
355              
356             =cut
357              
358             sub to_RA_TELESCOPE_OFFSET {
359 0     0 1   my $self = shift;
360 0           my $FITS_headers = shift;
361 0           my $raoffset = 0.0;
362              
363 0 0 0       if ( exists $FITS_headers->{"CAT-DEC"} &&
      0        
364             exists $FITS_headers->{"CAT-RA"} && exists $FITS_headers->{RA} ) {
365              
366             # Obtain the reference and telescope sky positions measured in degrees.
367 0           my $refra = $self->hms_to_degrees( $FITS_headers->{"CAT-RA"} );
368 0           my $ra = $self->hms_to_degrees( $FITS_headers->{RA} );
369 0           my $refdec = $self->dms_to_degrees( $FITS_headers->{"CAT-DEC"} );
370              
371             # Find the offset between the positions in arcseconds on the sky.
372 0           $raoffset = 3600.0 * ( $ra - $refra ) * $self->cosdeg( $refdec );
373             }
374              
375             # The sense is reversed compared with UKIRT, as these measure the
376             # place son the sky, not the motion of the telescope.
377 0           return -1.0 * $raoffset;
378             }
379              
380             =item B<to_ROTATION>
381              
382             Returns the orientation of the detector in degrees anticlockwise
383             from north via east.
384              
385             =cut
386              
387             sub to_ROTATION {
388 0     0 1   my $self = shift;
389 0           my $FITS_headers = shift;
390 0           return $self->rotation( $FITS_headers );
391             }
392              
393             =item B<to_SPEED_GAIN>
394              
395             Returns the speed gain. This is either "Normal" or "HiGain", the
396             selection depending on the value of the C<CCDSPEED> keyword.
397              
398             =cut
399              
400             # Fixed values for the gain depend on the camera (SW or LW), and for LW
401             # the readout mode.
402             sub to_SPEED_GAIN {
403 0     0 1   my $self = shift;
404 0           my $FITS_headers = shift;
405 0           my $spd_gain;
406 0           my $speed = $FITS_headers->{CCDSPEED};
407 0 0         if ( $speed =~ /SLOW/ ) {
408 0           $spd_gain = "Normal";
409             } else {
410 0           $spd_gain = "HiGain";
411             }
412 0           return $spd_gain;
413             }
414              
415             =item B<to_STANDARD>
416              
417             Returns whether or not the observation is of a standard source. It is
418             deemed to be a standard when the C<OBSTYPE> keyword is "STANDARD".
419              
420             =cut
421              
422             sub to_STANDARD {
423 0     0 1   my $self = shift;
424 0           my $FITS_headers = shift;
425 0           my $standard = 0;
426 0           my $type = $FITS_headers->{OBSTYPE};
427 0 0         if ( uc( $type ) eq "STANDARD" ) {
428 0           $standard = 1;
429             }
430 0           return $standard;
431             }
432              
433             =item B<to_UTDATE>
434              
435             Returns the UT date as C<Time::Piece> object. It copes with non-standard
436             format in C<DATE-OBS>.
437              
438             =cut
439              
440             sub to_UTDATE {
441 0     0 1   my $self = shift;
442 0           my $FITS_headers = shift;
443 0           return $self->get_UT_date( $FITS_headers );
444             }
445              
446             =item B<to_UTEND>
447              
448             Returns the UT time of the end of the observation as a C<Time::Piece> object.
449              
450             =cut
451              
452             sub to_UTEND {
453 0     0 1   my $self = shift;
454 0           my $FITS_headers = shift;
455              
456             # This is the approximate end UT.
457 0           my $start = $self->to_UTSTART( $FITS_headers );
458 0           return $self->_add_seconds( $start, $FITS_headers->{EXPTIME} );
459             }
460              
461             =item B<to_UTSTART>
462              
463             Returns an estimated UT time of the start of the observation as a
464             C<Time::Piece> object. The start time is derived from the C<DATE-OBS>
465             keyword and if C<DATE-OBS> only supplies a date, the time from the
466             C<UTSTART> keyword is appended before conversaion to a C<Time::Piece>
467             object.
468              
469             =cut
470              
471             sub to_UTSTART {
472 0     0 1   my $self = shift;
473 0           my $FITS_headers = shift;
474 0           my $return;
475 0 0         if ( exists $FITS_headers->{'DATE-OBS'} ) {
476 0           my $iso;
477 0 0         if ( $FITS_headers->{'DATE-OBS'} =~ /T/ ) {
    0          
478             # standard format
479 0           $iso = $FITS_headers->{'DATE-OBS'};
480             } elsif ( exists $FITS_headers->{UTSTART} ) {
481 0           $iso = $FITS_headers->{'DATE-OBS'}. "T" . $FITS_headers->{UTSTART};
482             }
483 0 0         $return = $self->_parse_iso_date( $iso ) if $iso;
484             }
485 0           return $return;
486             }
487              
488             =item B<to_X_LOWER_BOUND>
489              
490             Returns the lower bound along the X-axis of the area of the detector
491             as a pixel index.
492              
493             =cut
494              
495             sub to_X_LOWER_BOUND {
496 0     0 1   my $self = shift;
497 0           my $FITS_headers = shift;
498 0           my @bounds = $self->getbounds( $FITS_headers );
499 0           return $bounds[ 0 ];
500             }
501              
502             =item B<to_X_REFERENCE_PIXEL>
503              
504             Specifies the X-axis reference pixel near the frame centre. It uses
505             the nominal reference pixel if that is correctly supplied, failing
506             that it takes the average of the bounds, and if these headers are also
507             absent, it uses a default which assumes the full array.
508              
509             =cut
510              
511             sub to_X_REFERENCE_PIXEL{
512 0     0 1   my $self = shift;
513 0           my $FITS_headers = shift;
514 0           my $xref;
515 0           my @bounds = $self->getbounds( $FITS_headers );
516 0 0 0       if ( $bounds[ 0 ] > 1 || $bounds[ 1 ] < 1024 ) {
517 0           $xref = nint( ( $bounds[ 0 ] + $bounds[ 1 ] ) / 2 );
518             } else {
519 0           $xref = 512;
520             }
521 0           return $xref;
522             }
523              
524             =item B<to_X_UPPER_BOUND>
525              
526             Returns the upper bound along the X-axis of the area of the detector
527             as a pixel index.
528              
529             =cut
530              
531             sub to_X_UPPER_BOUND {
532 0     0 1   my $self = shift;
533 0           my $FITS_headers = shift;
534 0           my @bounds = $self->getbounds( $FITS_headers );
535 0           return $bounds[ 1 ];
536             }
537              
538             =item B<to_Y_LOWER_BOUND>
539              
540             Returns the lower bound along the Y-axis of the area of the detector
541             as a pixel index.
542              
543             =cut
544              
545             sub to_Y_LOWER_BOUND {
546 0     0 1   my $self = shift;
547 0           my $FITS_headers = shift;
548 0           my @bounds = $self->getbounds( $FITS_headers );
549 0           return $bounds[ 2 ];
550             }
551              
552             =item B<to_Y_REFERENCE_PIXEL>
553              
554             Specifies the Y-axis reference pixel near the frame centre. It uses
555             the nominal reference pixel if that is correctly supplied, failing
556             that it takes the average of the bounds, and if these headers are also
557             absent, it uses a default which assumes the full array.
558              
559             =cut
560              
561             sub to_Y_REFERENCE_PIXEL{
562 0     0 1   my $self = shift;
563 0           my $FITS_headers = shift;
564 0           my $yref;
565 0           my @bounds = $self->getbounds( $FITS_headers );
566 0 0 0       if ( $bounds[ 2 ] > 1 || $bounds[ 3 ] < 1024 ) {
567 0           $yref = nint( ( $bounds[ 2 ] + $bounds[ 3 ] ) / 2 );
568             } else {
569 0           $yref = 512;
570             }
571 0           return $yref;
572             }
573              
574             =item B<to_Y_UPPER_BOUND>
575              
576             Returns the upper bound along the Y-axis of the area of the detector
577             as a pixel index.
578              
579             =cut
580              
581             sub to_Y_UPPER_BOUND {
582 0     0 1   my $self = shift;
583 0           my $FITS_headers = shift;
584 0           my @bounds = $self->getbounds( $FITS_headers );
585 0           return $bounds[ 3 ];
586             }
587              
588             =back
589              
590             # Supplementary methods for the translations
591             # ------------------------------------------
592              
593             =head1 HELPER ROUTINES
594              
595             These are INGRID-specific helper routines.
596              
597             =over 4
598              
599             =item B<dms_to_degrees>
600              
601             Converts a sky angle specified in d:m:s format into decimal degrees.
602             The argument is the sexagesimal-format angle.
603              
604             =cut
605              
606             sub dms_to_degrees {
607 0     0 1   my $self = shift;
608 0           my $sexa = shift;
609 0           my $dms;
610 0 0         if ( defined( $sexa ) ) {
611 0           my @pos = split( /:/, $sexa );
612 0           $dms = $pos[ 0 ] + $pos[ 1 ] / 60.0 + $pos [ 2 ] / 3600.;
613             }
614 0           return $dms;
615             }
616              
617             # Obtain the detector bounds from a section in [xl:xu,yl:yu] syntax.
618             # If the RTDATSEC header is absent, use a default which corresponds
619             # to the full array.
620             sub getbounds{
621 0     0 0   my $self = shift;
622 0           my $FITS_headers = shift;
623 0           my @bounds = ( 1, 1024, 1, 1024 );
624 0 0         if ( exists $FITS_headers->{RTDATSEC} ) {
625 0           my $section = $FITS_headers->{RTDATSEC};
626 0           $section =~ s/\[//;
627 0           $section =~ s/\]//;
628 0           $section =~ s/,/:/g;
629 0           @bounds = split( /:/, $section );
630             }
631 0           return @bounds;
632             }
633              
634             =item B<get_UT_date>
635              
636             Returns the UT date in YYYYMMDD format. It parses the non-standard
637             ddMmmyy C<DATE-OBS> keyword.
638              
639             =cut
640              
641             sub get_UT_date {
642 0     0 1   my $self = shift;
643 0           my $FITS_headers = shift;
644              
645             # This is UT start and time.
646 0           my $dateobs = $FITS_headers->{"DATE-OBS"};
647              
648             # Extract out the data in yyyymmdd format.
649 0           return substr( $dateobs, 0, 4 ) . substr( $dateobs, 5, 2 ) . substr( $dateobs, 8, 2 )
650             }
651              
652             =item B<hms_to_degrees>
653              
654             Converts a sky angle specified in h:m:s format into decimal degrees.
655             It takes no account of latitude. The argument is the sexagesimal
656             format angle.
657              
658             =cut
659              
660             sub hms_to_degrees {
661 0     0 1   my $self = shift;
662 0           my $sexa = shift;
663 0           my $hms;
664 0 0         if ( defined( $sexa ) ) {
665 0           my @pos = split( /:/, $sexa );
666 0           $hms = 15.0 * ( $pos[ 0 ] + $pos[ 1 ] / 60.0 + $pos [ 2 ] / 3600. );
667             }
668 0           return $hms;
669             }
670              
671             =item B<rotation>
672              
673             Derives the rotation angle in degrees from the C<ROTSKYPA> keyword, with a
674             default of 0.0.
675              
676             =cut
677              
678             sub rotation{
679 0     0 1   my $self = shift;
680 0           my $FITS_headers = shift;
681 0           my $rotangle = 0.0;
682              
683 0 0         if ( exists $FITS_headers->{ROTSKYPA} ) {
684 0           $rotangle = $FITS_headers->{ROTSKYPA};
685             }
686 0           return $rotangle;
687             }
688              
689             =back
690              
691             =head1 SEE ALSO
692              
693             C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::UKIRT>.
694              
695             =head1 AUTHOR
696              
697             Malcolm J. Currie E<lt>mjc@star.rl.ac.ukE<gt>
698             Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
699             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>.
700              
701             =head1 COPYRIGHT
702              
703             Copyright (C) 2008 Science and Technology Facilities Council.
704             Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
705             All Rights Reserved.
706              
707             This program is free software; you can redistribute it and/or modify it under
708             the terms of the GNU General Public License as published by the Free Software
709             Foundation; either Version 2 of the License, or (at your option) any later
710             version.
711              
712             This program is distributed in the hope that it will be useful,but WITHOUT ANY
713             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
714             PARTICULAR PURPOSE. See the GNU General Public License for more details.
715              
716             You should have received a copy of the GNU General Public License along with
717             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
718             Place, Suite 330, Boston, MA 02111-1307, USA.
719              
720             =cut
721              
722             1;