File Coverage

blib/lib/Astro/FITS/HdrTrans.pm
Criterion Covered Total %
statement 94 107 87.8
branch 28 50 56.0
condition 16 36 44.4
subroutine 14 15 93.3
pod 7 8 87.5
total 159 216 73.6


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Astro::FITS::HdrTrans - Translate FITS headers to standardised form
5              
6             =head1 SYNOPSIS
7              
8             use Astro::FITS::HdrTrans qw/ translate_from_FITS
9             translate_to_FITS /;
10              
11             %generic_headers = translate_from_FITS(\%FITS_headers,
12             frameset => $frameset);
13              
14             %FITS_headers = translate_to_FITS(\%generic_headers);
15              
16             @headers = Astro::FITS::HdrTrans->generic_headers();
17             @classes = Astro::FITS::HdrTrans->translation_classes();
18              
19             =head1 DESCRIPTION
20              
21             Converts information contained in instrument-specific FITS headers to
22             and from generic headers. A list of generic headers are given at the end
23             of the module documentation.
24              
25             =cut
26              
27             use 5.006;
28 53     53   63800 use strict;
  53         160  
29 53     53   235 use warnings;
  53         105  
  53         1062  
30 53     53   253 use warnings::register;
  53         92  
  53         1878  
31 53     53   320 use Carp;
  53         103  
  53         9023  
32 53     53   325  
  53         101  
  53         2984  
33             use vars qw/ $VERSION $DEBUG @ISA /;
34 53     53   259  
  53         98  
  53         2830  
35             use Exporter 'import';
36 53     53   262 our @EXPORT_OK = qw( translate_from_FITS translate_to_FITS );
  53         105  
  53         52942  
37              
38             $VERSION = '1.65';
39             $DEBUG = 0;
40              
41             # The reference list of classes we can try This list should be
42             # extended whenever new translation tables are added. They should
43             # have a corresponding Astro::FITS::HdrTrans:: module available Note
44             # that there are more perl modules in the distribution than are listed
45             # here. This is because some perl modules provide a base set of
46             # translations shared by multiple instruments.
47              
48             my @REF_CLASS_LIST = qw/ ACSIS IRCAM CGS4New CGS4Old UIST UFTI RxH3
49             JCMT_GSD JCMT_GSD_DB MICHELLE SCUBA SCUBA2 UKIRTDB WFCAM IRIS2 SOFI
50             ISAAC NACO INGRID GMOS SPEX NIRI ClassicCam CURVE LCOSBIG_CC
51             LCOSBIG_1m0 LCOSBIG_0m4 LCOSBIG_0m8 LCOSINISTRO_1m0
52             LCOFLOYDS LCOMEROPE LCOSPECTRAL LCOFLI_1m0/;
53              
54             # This is the actual list that is currently supported. It should always
55             # default to the reference list
56             my @local_class_list = @REF_CLASS_LIST;
57              
58             =head1 CLASS METHODS
59              
60             Some class methods are available
61              
62             =over 4
63              
64             =item B<generic_headers>
65              
66             Returns a list of all the generic headers that can in principal be
67             used for header translation. Note that not all the instruments support
68             all the headers.
69              
70             @hdrs = Astro::FITS::HdrTrans->generic_headers();
71              
72             =cut
73              
74             my @generic_headers = qw(
75             AIRMASS_START
76             AIRMASS_END
77             ALTITUDE
78             AMBIENT_TEMPERATURE
79             AZIMUTH_START
80             AZIMUTH_END
81             BACKEND
82             BACKEND_SECTIONS
83             BANDWIDTH_MODE
84             BOLOMETERS
85             CAMERA
86             CAMERA_NUMBER
87             CHOP_ANGLE
88             CHOP_COORDINATE_SYSTEM
89             CHOP_FREQUENCY
90             CHOP_THROW
91             CONFIGURATION_INDEX
92             COORDINATE_SYSTEM
93             COORDINATE_UNITS
94             COORDINATE_TYPE
95             CYCLE_LENGTH
96             DATA_UNITS
97             DEC_BASE
98             DEC_SCALE
99             DEC_SCALE_UNITS
100             DEC_TELESCOPE_OFFSET
101             DETECTOR_BIAS
102             DETECTOR_INDEX
103             DETECTOR_READ_TYPE
104             DOME_OPEN
105             DR_GROUP
106             DR_RECIPE
107             ELEVATION_START
108             ELEVATION_END
109             EPOCH
110             EQUINOX
111             EXPOSURE_TIME
112             FILE_FORMAT
113             FILENAME
114             FILTER
115             FRONTEND
116             FOURIER_TRANSFORM_SPECTROMETER
117             GAIN
118             GALACTIC_LATITUDE
119             GALACTIC_LONGITUDE
120             GRATING_DISPERSION
121             GRATING_NAME
122             GRATING_ORDER
123             GRATING_WAVELENGTH
124             HUMIDITY
125             INSTRUMENT
126             INST_DHS
127             LATITUDE
128             LONGITUDE
129             MSBID
130             MSB_TRANSACTION_ID
131             NSCAN_POSITIONS
132             NUMBER_OF_COADDS
133             NUMBER_OF_CYCLES
134             NUMBER_OF_DETECTORS
135             NUMBER_OF_EXPOSURES
136             NUMBER_OF_FREQUENCIES
137             NUMBER_OF_JITTER_POSITIONS
138             NUMBER_OF_MICROSTEP_POSITIONS
139             NUMBER_OF_OFFSETS
140             NUMBER_OF_READS
141             NUMBER_OF_SUBFRAMES
142             NUMBER_OF_SUBSCANS
143             OBJECT
144             OBSERVATION_ID
145             OBSERVATION_ID_SUBSYSTEM
146             OBSERVATION_MODE
147             OBSERVATION_NUMBER
148             OBSERVATION_TYPE
149             OBSERVED_SIDEBAND
150             POLARIMETER
151             POLARIMETRY
152             PROJECT
153             RA_BASE
154             RA_SCALE
155             RA_SCALE_UNITS
156             RA_TELESCOPE_OFFSET
157             RECEIVER_TEMPERATURE
158             REFERENCE_LOCATION
159             REMOTE
160             REST_FREQUENCY
161             ROTATION
162             SAMPLE_MODE
163             SAMPLING
164             SCAN_INCREMENT
165             SCAN_PATTERN
166             SEEING
167             SHIFT_TYPE
168             SIDEBAND_MODE
169             SLIT_ANGLE
170             SLIT_NAME
171             SLIT_WIDTH
172             SPECIES
173             SPEED_GAIN
174             STANDARD
175             SUBSYSTEM_IDKEY
176             SURVEY
177             SWITCH_MODE
178             SYSTEM_TEMPERATURE
179             SYSTEM_VELOCITY
180             TAI_UTC_CORRECTION
181             TAU
182             TELESCOPE
183             TILE_NUMBER
184             TRACKING_SIDEBAND
185             TRANSITION
186             USER_AZIMUTH_CORRECTION
187             USER_ELEVATION_CORRECTION
188             UTDATE
189             UTEND
190             UTSTART
191             UT1_UTC_CORRECTION
192             VELOCITY
193             VELOCITY_REFERENCE_FRAME
194             VELOCITY_TYPE
195             WAVEPLATE_ANGLE
196             WIND_BLIND
197             XBINNING
198             YBINNING
199             X_APERTURE
200             Y_APERTURE
201             X_BASE
202             Y_BASE
203             X_OFFSET
204             Y_OFFSET
205             X_REFERENCE_PIXEL
206             Y_REFERENCE_PIXEL
207             X_REQUESTED
208             Y_REQUESTED
209             X_SCALE
210             Y_SCALE
211             X_DIM
212             Y_DIM
213             X_LOWER_BOUND
214             X_UPPER_BOUND
215             Y_LOWER_BOUND
216             Y_UPPER_BOUND
217             ZENITH_DISTANCE_START
218             ZENITH_DISTANCE_END
219             );
220              
221             my $class = shift;
222             return @generic_headers;
223 35     35 1 70 }
224 35         688  
225             =item B<translation_classes>
226              
227             Return the names of all the translation classes that will be
228             tried when translating a FITS header.
229              
230             @classes = Astro::FITS::HdrTrans->translation_classes();
231              
232             If arguments are supplied, the list of translation classes is
233             set to the supplied values.
234              
235             Astro::FITS::HdrTrans->translation_classes( @new );
236              
237             =cut
238              
239             my $class = shift;
240             if (@_) {
241             @local_class_list = @_;
242 36     36 1 74 }
243 36 50       119 return @local_class_list;
244 0         0 }
245              
246 36         328 =item B<reset_translation_classes>
247              
248             Revert back to the reference list of translation classes.
249              
250             Astro::FITS::HdrTrans->reset_translation_classes;
251              
252             Useful if the list has been modified for a specific translation.
253              
254             =cut
255              
256             my $class = shift;
257             @local_class_list = @REF_CLASS_LIST;
258             }
259              
260 0     0 0 0 =item B<push_class>
261 0         0  
262             Allows additional classes to be pushed on the list of valid
263             translation classes.
264              
265             Astro::FITS::HdrTrans->push_class( $class );
266              
267             The class[es] can be specified either as a list or a reference to
268             an array.
269              
270             =cut
271              
272             my $class = shift;
273             my @new = @_;
274              
275             # check for array ref
276             @new = ( ref($new[0]) ? @{ $new[0] } : @new );
277 2     2 1 1056 push(@local_class_list, @new);
278 2         3 return @local_class_list;
279             }
280              
281 2 50       5 =back
  0         0  
282 2         4  
283 2         3 =head1 FUNCTIONS
284              
285             The following functions are available. They can be exported but are
286             not exported by default.
287              
288             =over 4
289              
290             =item B<translate_from_FITS>
291              
292             Converts a hash containing instrument-specific FITS headers into a hash
293             containing generic headers.
294              
295             %generic_headers = translate_from_FITS(\%FITS_headers,
296             class => \@classes,
297             prefix => 'ORAC_',
298             frameset => $frameset,
299             );
300              
301             This method takes a reference to a hash containing untranslated headers,
302             and a hash reference containing the following optional keys:
303              
304             =over 8
305              
306             =item *
307              
308             class - A reference to a list of subclasses to try to use for header
309             translations. This list overrides the default list. If left blank, the
310             default list will be used, as returned by the C<translation_classes>
311             method. This is sometimes required to break degeneracy when you know
312             you have a limited set of valid instruments.
313              
314             =item *
315              
316             frameset - An AST FrameSet describing the WCS. The WCS in this
317             FrameSet will override any WCS information contained in the FITS
318             headers.
319              
320             =item *
321              
322             prefix - A string prefix to add to the front of every translated header name.
323             For example, if this prefix is set to 'ORAC_', then the translated header
324             for the instrument value, whose key is normally 'INSTRUMENT', will have a
325             key named 'ORAC_INSTRUMENT'. The original keys will not be in the
326             returned hash. If left blank, no prefix will be added.
327              
328             =back
329              
330             This method returns a hash of generic headers. This function dies if
331             the header translation fails in any way.
332              
333             =cut
334              
335             my $FITS_header = shift;
336             my %options = @_;
337              
338             # translation classes
339             my @classes;
340             if ( exists( $options{class} ) &&
341 20     20 1 901702 defined( $options{class} ) &&
342 20         62 ref( $options{class} ) eq 'ARRAY' ) {
343             @classes = @{$options{class}};
344             }
345 20         38  
346 20 0 33     98 my $prefix;
      33        
347             if ( exists( $options{prefix} ) &&
348             defined( $options{prefix} ) ) {
349 0         0 $prefix = $options{prefix};
  0         0  
350             }
351              
352 20         42 my $frameset;
353 20 100 66     71 if ( exists( $options{frameset} ) &&
354             defined( $options{frameset} ) ) {
355 1         3 $frameset = $options{frameset};
356             }
357              
358 20         43 # determine which class can be used for the translation
359 20 50 33     91 my $class = determine_class( $FITS_header, \@classes, 1 );
360              
361 0         0 # we know this class is already loaded so do the translation
362             return $class->translate_from_FITS( $FITS_header,
363             prefix => $prefix,
364             frameset => $frameset );
365 20         78  
366             }
367              
368 20         271 =item B<translate_to_FITS>
369              
370             Converts a hash containing generic headers into one containing
371             instrument-specific FITS headers.
372              
373             %FITS_headers = translate_to_FITS(\%generic_headers,
374             class => \@classes,
375             );
376              
377             This method takes a reference to a hash containing untranslated
378             headers, and a hash reference containing the following optional
379             keys:
380              
381             =over 8
382              
383             =item *
384              
385             class - A reference to a list of subclasses to try to use for header
386             translations. This list overrides the default list. If left blank, the
387             default list will be used.
388              
389             =item *
390              
391             prefix - A string prefix to remove from the generic header key
392             before doing header translation. Why you would want to do this
393             is if you've used a prefix in the C<translate_from_FITS> call, and
394             want to translate back from the generic headers returned from
395             that method. If left blank, no prefix will be removed.
396              
397             =back
398              
399             This method returns a hash of instrument-specific headers. This
400             function dies if the header translation fails in any way.
401              
402             =cut
403              
404             my $generic_header = shift;
405             my %options = @_;
406              
407             my @classes;
408             if ( exists( $options{class} ) &&
409             defined( $options{class} ) &&
410             ref( $options{class} ) eq 'ARRAY' ) {
411 15     15 1 37102 @classes = @{$options{class}};
412 15         39 }
413              
414 15         34  
415 15 0 33     68 my $prefix;
      33        
416             if ( exists( $options{prefix} ) &&
417             defined( $options{prefix} ) ) {
418 0         0 $prefix = $options{prefix};
  0         0  
419             } else {
420             $prefix = '';
421             }
422 15         32  
423 15 100 66     57 # We need to strip off any prefix before figuring out what
424             # class we need to use.
425 1         2 my %stripped_header = clean_prefix( $generic_header, $prefix );
426              
427 14         34 # Check the UTSTART and UTEND headers to make sure they're
428             # Time::Piece objects.
429             for my $h (qw/ UTSTART UTEND / ) {
430             if ( exists( $stripped_header{$h} ) &&
431             defined( $stripped_header{$h} ) &&
432 15         57 ! UNIVERSAL::isa( $stripped_header{$h}, "Time::Piece" ) ) {
433             warnings::warnif( "Warning: $h generic header is not a Time::Piece object" );
434             }
435             }
436 15         71  
437 30 50 33     237 # determine which class can be used for the translation
      33        
438             my $class = determine_class( \%stripped_header, \@classes, 0 );
439              
440 0         0 return $class->translate_to_FITS( \%stripped_header );
441              
442             }
443              
444             =item B<determine_class>
445 15         50  
446             Determine which class should be used for the translation (either way).
447 15         113 It is given a reference to the header hash and a reference to an array
448             of classes which can be queried.
449              
450             $class = determine_class( \%hdr, \@classes, $fromfits );
451              
452             The classes are loaded for each test. Failure to load indicates failure
453             to translate. If the classes are undefined, the default internal list
454             will be used.
455              
456             The third argument is a boolean indicating whether the class is being
457             used to translate from FITS (true) or to FITS (false). This is used
458             for error message clarity.
459              
460             This function can be useful to allow a single header translation to be
461             calculated without requiring that all translation are performed. For example,
462              
463             $class = Astro::FITS::HdrTrans::determine_class( \%hdr, undef, 1 );
464             $value = $class->to_OBSERVATION_ID( \%hdr, $frameset );
465              
466             If the key _TRANSLATION_CLASS exists and this class allows translation
467             and no override classes have been specified, that class is returned
468             without checking all classes. This key is automatically filled in when
469             a translation from fits is executed.
470              
471             =cut
472              
473             my $hdr = shift;
474             my $classes = shift;
475             my $fromfits = shift;
476              
477             # Default classes if empty or undef
478             my @defclasses = __PACKAGE__->translation_classes;
479             if (!defined $classes || !@$classes) {
480             # see if we have an override
481 36     36 1 212 if (exists $hdr->{_TRANSLATION_CLASS} && defined $hdr->{_TRANSLATION_CLASS}) {
482 36         77 my $class = $hdr->{_TRANSLATION_CLASS};
483 36         67 my $loaded = eval "require $class";
484             if ($loaded) {
485             if ($class->can("can_translate") && $class->can_translate($hdr) ) {
486 36         235 return $class;
487 36 50 66     199 }
488             }
489 36 100 66     272 }
490 16         37 # did not have an override so use defaults
491 16         1051 $classes = \@defclasses;
492 16 50       73 }
493 16 50 33     313  
494 16         82 # Determine the class name so we can use the appropriate subclass
495             # for header translations. We're going to use the "can_translate" method
496             # in each subclass listed in @$classes.
497             my %result = ();
498             my $base = "Astro::FITS::HdrTrans::";
499 20         302 foreach my $subclass ( @$classes ) {
500              
501             my $class = $base.$subclass;
502              
503             print "Trying class $class\n" if $DEBUG;
504              
505 20         42 # Try a class and if it fails to load, skip
506 20         40 eval "require $class";
507 20         46 if ( $@ ) {
508             print "Error loading class $class: $@\n" if $DEBUG;
509 660         3851 }
510             next if ( $@ );
511 660 50       1140 if ( $class->can("can_translate") ) {
512             if ( $class->can_translate( $hdr ) ) {
513             print "Class $class matches\n" if $DEBUG;
514 660         27994 $result{$subclass}++;
515 660 50       2386 }
516 0 0       0 } else {
517             # What to do, what to do?
518 660 50       1328 }
519 660 50       4730 }
520 660 100       2125  
521 20 50       70 if ( ( scalar keys %result ) > 1 ) {
522 20         86 croak "Ambiguities in determining which header translations to use (".
523             join(",",keys %result).")";
524             }
525              
526             if ( ( scalar keys %result ) == 0 ) {
527             # We couldn't figure out which one to use.
528             croak "Unable to determine header translation subclass. No matches for these headers when trying to convert "
529 20 50       154 . ($fromfits ? 'from' : 'to' )
530 0         0 . " FITS using the following classes: ".join(", ",@$classes);
531             }
532              
533             # The class we wanted is the only key in the hash
534 20 50       77 my @matched = keys %result;
535             my $class = $base . $matched[0];
536 0 0       0  
537             return $class;
538             }
539              
540             =item B<clean_prefix>
541              
542 20         70 If a prefix has been used and a targetted conversion is required (which will not understand
543 20         56 the prefix) the prefix must first be removed. This function will remove the preifx, only
544             returning headers that contained the prefix.
545 20         167  
546             %cleaned = clean_prefix( \%header, $prefix );
547              
548             If prefix is an empty string or undefined, returns all headers.
549              
550             =cut
551              
552             my $href = shift;
553             my $prefix = shift;
554             return %$href unless $prefix;
555              
556             my %stripped_header;
557             while ( my ( $key, $value ) = each( %{$href} ) ) {
558             if ($key eq '_TRANSLATION_CLASS') {
559             # this should be retained
560             $stripped_header{$key} = $value;
561 16     16 1 1083 } elsif ($key =~ /^$prefix/) {
562 16         32 # only propagate keys that contain the prefix
563 16 100       589 $key =~ s/^$prefix//;
564             $stripped_header{$key} = $value;
565 2         3 }
566 2         4 }
  42         77  
567 40 100       115 return %stripped_header;
    100          
568             }
569 2         4  
570             =back
571              
572 36         76 =head1 NOTES
573 36         66  
574             Individual translations can be invoked explicitly if a class name is known.
575             The syntax for conversion from a FITS header to generic value is
576 2         17  
577             $result = $class->to_GENERIC_KEYWORD( \%header, $frameset );
578              
579             Frameset information (Starlink::AST object) is optional.
580              
581             The syntax for conversion from generic to FITS headers is:
582              
583             %fits = $class->from_GENERIC_KEYWORD( \%translated_hdr );
584              
585             Note that the conversion to FITS can result in multiple header items
586             and can require more than a single generic translated header item.
587              
588             If you are using a prefix, the general paradigm for converting a
589             translated header back to FITS is:
590              
591             my %cleaned = Astro::FITS::HdrTrans::clean_prefix( \%translated_hdr, $prefix );
592             my $class = Astro::FITS::HdrTrans::determine_class( \%cleaned, undef, 0 );
593             my %fits = $class->from_DR_RECIPE( \%cleaned );
594              
595              
596             =head1 AUTHOR
597              
598             Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
599             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>,
600             Malcolm J. Currie E<lt>mjc@jach.hawaii.eduE<gt>
601              
602             =head1 COPYRIGHT
603              
604             Copyright (C) 2007-2009, 2013 Science and Technology Facilities Council.
605             Copyright (C) 2003-2007 Particle Physics and Astronomy Research Council.
606             All Rights Reserved.
607              
608             This program is free software; you can redistribute it and/or modify it under
609             the terms of the GNU General Public License as published by the Free Software
610             Foundation; either Version 2 of the License, or (at your option) any later
611             version.
612              
613             This program is distributed in the hope that it will be useful, but WITHOUT ANY
614             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
615             PARTICULAR PURPOSE. See the GNU General Public License for more details.
616              
617             You should have received a copy of the GNU General Public License along with
618             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
619             Place, Suite 330, Boston, MA 02111-1307, USA.
620              
621             =cut
622              
623             1;