File Coverage

blib/lib/Astro/FITS/HdrTrans/Base.pm
Criterion Covered Total %
statement 205 239 85.7
branch 37 54 68.5
condition 14 30 46.6
subroutine 74 79 93.6
pod 37 65 56.9
total 367 467 78.5


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Astro::FITS::HdrTrans::Base - Base class for header translation
5              
6             =head1 SYNOPSIS
7              
8             use base qw/ Astro::FITS::HdrTrans::Base /;
9              
10             %generic = Astro::FITS::HdrTrans::Base->translate_from_FITS( \%fits );
11             %fits = Astro::FITS::HdrTrans::Base->translate_to_FITS( \%gen );
12              
13             =head1 DESCRIPTION
14              
15             This is the header translation base class. Not to be confused with
16             C<Astro::FITS::HdrTrans> itself, which is a high level abstraction
17             class. In general users should use C<Astro::FITS::HdrTrans>
18             for initiating header translations unless they know what they are
19             doing. Also C<Astro::FITS::HdrTrans> is the only public interface
20             to the header translation.
21              
22             =cut
23              
24             use 5.006;
25 66     66   1237574 use strict;
  63         565  
26 59     63   248 use warnings;
  58         139  
  70         1060  
27 55     59   239 use Carp;
  53         118  
  54         1200  
28 52     58   211 use Math::Trig qw/ deg2rad /;
  54         113  
  52         2769  
29 52     70   15878  
  52         405483  
  52         3803  
30             use vars qw/ $VERSION /;
31 52     55   399 use Astro::FITS::HdrTrans (); # for the generic header list
  52         318  
  52         3021  
32 52     53   22744  
  52         126  
  52         68744  
33             $VERSION = "1.65";
34              
35             =head1 PUBLIC METHODS
36              
37             All methods in this class are CLASS METHODS. No state is retained
38             outside of the hash argument.
39              
40             =over 4
41              
42             =item B<translate_from_FITS>
43              
44             Do the header translation from FITS for the specified class.
45              
46             %generic = $class->translate_to_FITS( \%fitshdr,
47             prefix => $prefix,
48             frameset => $wcs,
49             );
50              
51             Prefix is attached to the keys in the returned hash if it
52             is defined. The frameset is an optional Starlink::AST object.
53              
54             If a translation results in an undefined value (for example, if the
55             headers can represent both imaging and spectroscopy there may be no
56             requirement for a DISPERSION header), the result is not stored in the
57             translated hash.
58              
59             A list of failed translations is available in the _UNDEFINED_TRANSLATIONS
60             key in the generic hash. This points to a reference to an array of all
61             the failed generic translations.
62              
63             The class used for the translation is stored in the key _TRANSLATION_CLASS.
64             This can then be used to reverse the translation without having to
65             re-scan the headers.
66              
67             =cut
68              
69             my $class = shift;
70             my $FITS = shift;
71 20     20 1 46 my %opts = @_;
72 20         32  
73 20         80 my $prefix = '';
74             if ( exists( $opts{prefix} ) &&
75 20         43 defined( $opts{prefix} ) ) {
76 20 100 66     511 $prefix = $opts{prefix};
77             }
78 1         3  
79             my $frameset;
80             if ( exists( $opts{frameset} ) &&
81 20         95 defined( $opts{frameset} ) ) {
82 20 50 33     122 $frameset = $opts{frameset};
83             }
84 0         0  
85             croak "translate_from_FITS: Not a hash reference!"
86             unless (ref($FITS) && ref($FITS) eq 'HASH');
87 20 50 33     122  
88             # Now we need to loop over the known generic headers
89             # which we obtain from Astro::FITS::HdrTrans
90             my @GEN = Astro::FITS::HdrTrans->generic_headers;
91              
92 20         157 my %generic;
93             my @failed;
94 20         59 for my $g (@GEN) {
95             my $method = "to_$g";
96 20         57 if ($class->can( $method )) {
97 2880         4010 my $result = $class->$method( $FITS, $frameset );
98 2880 100       14237 if (defined $result) {
99 1162         19645 $generic{"$prefix$g"} = $result;
100 1162 100       18174 } else {
101 900         2530 push(@failed, $g);
102             }
103 262         512 }
104             }
105              
106             # store the failed translations (if we had any)
107             $generic{_UNDEFINED_TRANSLATIONS} = \@failed if @failed;
108              
109 20 50       152 # store the translation class
110             $generic{_TRANSLATION_CLASS} = $class;
111              
112 20         72 return %generic;
113             }
114 20         1142  
115             =item B<translate_to_FITS>
116              
117             Do the header translation from generic headers to FITS
118             for the specified class.
119              
120             %fits = $class->translate_to_FITS( \%generic );
121              
122             =cut
123              
124             my $class = shift;
125             my $generic = shift;
126              
127 15     17 1 34 croak "translate_to_FITS: Not a hash reference!"
128 15         32 unless (ref($generic) && ref($generic) eq 'HASH');
129              
130 15 50 33     82 # Now we need to loop over the known generic headers
131             # which we obtain from Astro::FITS::HdrTrans
132             my @GEN = Astro::FITS::HdrTrans->generic_headers;
133              
134             my %FITS;
135 15         60 for my $g (@GEN) {
136             my $method = "from_$g";
137 15         43 if ($class->can( $method )) {
138 15         42 %FITS = (%FITS,$class->$method( $generic ));
139 2160         3225 }
140 2160 100       9765  
141 780         18020 }
142              
143             return %FITS;
144             }
145              
146 15         392 =back
147              
148             =head1 PROTECTED METHODS
149              
150             These methods are available to translation subclasses and should
151             not be used by external classes.
152              
153             =over 4
154              
155             =item B<can_translate>
156              
157             Returns true if the supplied headers can be handled by this class.
158              
159             $cando = $class->can_translate( \%hdrs );
160              
161             The base class version of this method returns true if either the C<INSTRUME>
162             or C<INSTRUMENT> key exist and match the value returned by the
163             C<this_instrument> method. Comparisons are case-insensitive and can use
164             regular expressions on instrument name if provided by the base class.
165              
166              
167             =cut
168              
169             my $class = shift;
170             my $headers = shift;
171              
172             # get the reference instrument string
173 527     527 1 799 my $ref = $class->this_instrument();
174 527         645 return 0 unless defined $ref;
175              
176             # For consistency in subsequent algorithm convert
177 527         1827 # a string to a pattern match object
178 527 50       1165 if (not ref($ref)) {
179             $ref = quotemeta($ref);
180             $ref = qr/^$ref$/i;
181             }
182 527 100       1049  
183 243         499 # check against the FITS and Generic versions.
184 243         2835 my $inst;
185             for my $k (qw/ INSTRUME INSTRUMENT /) {
186             if (exists $headers->{$k} && defined $headers->{$k}) {
187             $inst = $headers->{$k};
188 527         755 last;
189 527         1197 }
190 540 100 66     1958 }
191 527         36334  
192 527         21832 # no recognizable instrument
193             return 0 unless defined $inst;
194              
195             # Now do the test
196             return ( $inst =~ $ref );
197 527 50       1213 }
198              
199             =item B<this_instrument>
200 527         3581  
201             Name of the instrument that can be translated by this class.
202             Defaults to an empty string. The method must be subclassed.
203              
204             $inst = $class->this_instrument();
205              
206             Can return a regular expresion object (C<qr>).
207              
208             =cut
209              
210             return "";
211             }
212              
213             =item B<valid_class>
214              
215 0     0 1 0 Historically this method was used to determine whether this class can
216             handle the supplied FITS headers. The headers can be either in
217             generic form or in FITS form.
218              
219             $isvalid = $class->valid_class( \%fits );
220              
221             The base class always returns false. This is a backwards compatibility
222             method to prevent mixing of translation modules from earlier release
223             of C<Astro::FITS::HdrTrans> with the current object-oriented version.
224             See the C<can_translate> method for the new interface.
225              
226             =cut
227              
228             return 0;
229             }
230              
231             =item B<_generate_lookup_methods>
232              
233             We generate the unit and constant mapping methods automatically from a
234 0     0 1 0 lookup table.
235              
236             Astro::FITS::HdrTrans::UKIRT->_generate_lookup_methods( \%const, \%unit);
237              
238             This method generates all the simple internal methods. Expects two arguments,
239             both references to hashes. The first is a reference to a hash with
240             constant mapping from FITS to generic (and no reverse mapping), the
241             second is a reference to a hash with unit mappings (both from and to
242             methods are created). The methods are placed into the package given
243             by the class supplied to the method.
244              
245             Astro::FITS::HdrTrans::UKIRT->_generate_lookup_methods( \%const, \%unit, \%null);
246              
247             Additionally, an optional third argument can be used to indicate
248             methods that should be null translations. This is a reference to an array
249             of generic keywords and should be used in the rare cases when a base
250             class implementation should be nullified. This will result in undefined
251             values in the generic hash but no value in the generic to FITS mapping.
252              
253             A fourth optional argument can specify those unit mappings that should
254             use the final entry in a subheader (if a subheader is present). Mainly
255             associated with END events such as AIRMASS_END or ELEVATION_END.
256              
257             Astro::FITS::HdrTrans::UKIRT->_generate_lookup_methods( \%const, \%unit,
258             \%null, \%endobs);
259              
260             These methods will have the standard interface of
261              
262             $generic = $class->_to_GENERIC_NAME( \%fits );
263             %fits = $class->_from_GENERIC_NAME( \%generic );
264              
265             Generic unit map translations use the via_subheader() method in scalar
266             context and so will retrieve the first sub header value if the keyword
267             is not present in the primary header.
268              
269             =cut
270              
271             my $class = shift;
272             my $const = shift;
273             my $unit = shift;
274             my $null = shift;
275             my $endobs = shift;
276              
277             # Have to go into a different package
278 512     512   957 my $p = "{\n package $class;\n";
279 512         736 my $ep = "\n}"; # close the scope
280 512         628  
281 512         645 # Loop over the keys to the unit mapping hash
282 512         642 # The keys are the GENERIC name
283             for my $key (keys %$unit) {
284              
285 512         1109 # Get the original FITS header name
286 512         975 my $fhdr = $unit->{$key};
287              
288             # print "Processing $key and $ohdr and $fhdr\n";
289              
290 512         1925 # First generate the code to generate Generic headers
291             my $subname = "to_$key";
292             my $sub = qq/ $p sub $subname { scalar \$_[0]->via_subheader_undef_check(\$_[1],\"$fhdr\"); } $ep /;
293 4856         8667 eval "$sub";
294             #print "Sub: $sub\n";
295              
296             # Now the from
297             $subname = "from_$key";
298 4856         7421 $sub = qq/ $p sub $subname { (\"$fhdr\", \$_[1]->{\"$key\"}); } $ep/;
299 4856         8980 eval "$sub";
300 4856     1 0 289281 #print "Sub: $sub\n";
  1     15 0 4  
  15     2 1 69  
  2     6 1 11  
  6     25 1 30  
  25     8 0 93  
  8     6 0 41  
  6     26 0 24  
  26     24 0 99  
  24     40 0 101  
  40     70 0 166  
  70     51 0 377  
  51     76 0 258  
  76     36 0 526  
  36     63 1 173  
  63     30 1 415  
  30     56 1 131  
  56     35 0 244  
  35     27 0 153  
  27     33 1 138  
  33     17 1 145  
  17     23 1 86  
  23     14 1 108  
  14     24 0 113  
  24     10 0 104  
  10     8 0 53  
  8     2 0 72  
  2         10  
301              
302             }
303              
304 4856         9051 # and the CONSTANT mappings (only to_GENERIC_NAME)
305 4856         9756 for my $key (keys %$const) {
306 4856     28 1 274504 my $subname = "to_$key";
  28     43 1 113  
  43     26 1 225  
  26     35 1 131  
  35     28 1 190  
  28     12 1 787  
  12     17 0 120  
  17     21 0 114  
  21     27 0 148  
  27     48 0 209  
  48     50 0 437  
  50     30 1 472  
  30     44 1 245  
  44     41 1 522  
  41     37 0 959  
  37     26 0 431  
  26     36 1 415  
  36     50 1 472  
  50     35 1 591  
  35     33 1 584  
  33     1 0 410  
  1         3  
307             my $val = $const->{$key};
308             # A method so no gain in using a null prototype
309             my $sub = qq/ $p sub $subname { \"$val\" } $ep /;
310             eval "$sub";
311             }
312 512         1806  
313 793         1668 # the null mappings
314 793         1201 if (defined $null) {
315             for my $key (@$null) {
316 793         1855 # to generic
317 793     4 1 38086 my $subname = "to_$key";
  4     17 1 59  
  17     21 1 190  
  21     21 0 245  
  11     12 0 36  
  19     18 0 94  
  23     16 1 155  
  21         78  
318             my $sub = qq/ $p sub $subname { } $ep /;
319             eval "$sub";
320              
321 512 100       1734 # to generic
322 272         596 $subname = "from_$key";
323             $sub = qq/ $p sub $subname { return (); } $ep /;
324 62         142 eval "$sub";
325 62         154 }
326 62         2697 }
327              
328             # the mappings that are unit mappings but from the end of a subheader
329 62         134 # group (eg ELEVATION_END)
330 62         165 if (defined $endobs) {
331 62         2895 for my $key (keys %$endobs) {
332              
333             # Get the original FITS header name
334             my $fhdr = $endobs->{$key};
335              
336             # print "Processing $key and $ohdr and $fhdr\n";
337 512 100       1711  
338 30         91 # First generate the code to generate Generic headers
339             my $subname = "to_$key";
340             my $sub = qq/ $p sub $subname {
341 60         115 my \@allresults = \$_[0]->via_subheader_undef_check(\$_[1],\"$fhdr\");
342             return \$allresults[-1];
343             } $ep /;
344             eval "$sub";
345             #print "Sub: $sub\n";
346 60         116  
347 60         159 # Now the from
348             $subname = "from_$key";
349             $sub = qq/ $p sub $subname { (\"$fhdr\", \$_[1]->{\"$key\"}); } $ep/;
350             eval "$sub";
351 60         4303 #print "Sub: $sub\n";
352              
353             }
354             }
355 60         134  
356 60         165 }
357 60         3454  
358             =item B<nint>
359              
360             Return the nearest integer to a supplied floating point
361             value. 0.5 is rounded up.
362              
363             $int = Astro::FITS::HdrTrans->nint( $value );
364              
365             =cut
366              
367             my $class = shift;
368             my $value = shift;
369              
370             if ($value >= 0) {
371             return (int($value + 0.5));
372             } else {
373             return (int($value - 0.5));
374             }
375 27     17 1 118 }
376 13         48  
377             =item B<_parse_iso_date>
378 9 50       36  
379 8         25 Converts a UT date in form YYYY-MM-DDTHH:MM:SS.sss into a date
380             object (Time::Piece).
381 0         0  
382             $object = $trans->_parse_iso_date( $date );
383              
384             =cut
385              
386             my $self = shift;
387             my $datestr = shift;
388             my $return;
389             if (defined $datestr) {
390             # Not part of standard but we can deal with it
391             $datestr =~ s/Z//g;
392             # Time::Piece can not do fractional seconds. Should switch to DateTime
393             $datestr =~ s/\.\d+$//;
394             # parse
395 65     74   130 $return = Time::Piece->strptime( $datestr, "%Y-%m-%dT%T" );
396 65         101 }
397 65         87 return $return;
398 65 50       162 }
399              
400 65         164 =item B<_parse_yyyymmdd_date>
401              
402 65         171 Converts a UT date in format YYYYMMDD into a date object.
403              
404 65         526 $ojbect = $trans->_parse_yyyymmdd_date( $date, $sep );
405              
406 65         3978 Where $sep is the separator string and can be an empty string.
407             This allows 20090215, 2009-02-15 and 2009:02:15 to be parsed
408             by the same routine by using '', '-' and ':' respectively.
409              
410             =cut
411              
412             my $self = shift;
413             my $datestr = shift;
414             my $sep = shift;
415             $sep = '' unless defined $sep;
416              
417             # OSX Leopard has a completely broken strptime that can not
418             # handle %Y%m%d. We need to change the string to make it
419             # into a parseable form (or switch to DateTime).
420             if (!$sep) {
421             $sep = "-";
422 8     13   19 $datestr = join($sep, substr($datestr,0,4),
423 8         15 substr($datestr,4,2),
424 8         12 substr($datestr,6));
425 8 50       25 }
426              
427             return Time::Piece->strptime( $datestr,join($sep,'%Y','%m','%d') );
428             }
429              
430 8 100       22 =item B<_add_seconds>
431 1         3  
432 1         6 Add the supplied number of seconds to the supplied time object
433             and return a new object.
434              
435             $new = $trans->_add_seconds( $base, $delta );
436              
437 8         69 =cut
438              
439             my $self = shift;
440             my $base = shift;
441             my $delta = shift;
442             return ($base + Time::Seconds->new( $delta ) );
443             }
444              
445             =item B<_utdate_to_object>
446              
447             Converts a UT date in YYYYMMDD format to a date object at midnight.
448              
449             $obj = $trans->_utdate_to_object( $YYYYMMDD );
450 0     1   0  
451 0         0 =cut
452 0         0  
453 0         0 my $self = shift;
454             my $utdate = shift;
455             my $year = substr($utdate, 0, 4);
456             my $month= substr($utdate, 4, 2);
457             my $day = substr($utdate, 6, 2);
458             my $basedate = $self->_parse_iso_date( $year."-".$month ."-".$day.
459             "T00:00:00");
460             return $basedate;
461             }
462              
463             =item B<cosdeg>
464              
465 0     0   0 Return the cosine of the angle. The angle must be in degrees.
466 0         0  
467 0         0 =cut
468 0         0  
469 0         0 my $self = shift;
470 0         0 my $deg = shift;
471             cos( deg2rad($deg) );
472 0         0 }
473              
474             =item B<sindeg>
475              
476             Return the sine of the angle. The angle must be in degrees.
477              
478             =cut
479              
480             my $self = shift;
481             my $deg = shift;
482 0     0 1 0 sin( deg2rad($deg) );
483 0         0 }
484 0         0  
485             =item B<via_subheader>
486              
487             For the supplied FITS header item, first check the primary header
488             for existence, then check SUBHEADERS, then check "In" named subheaders.
489              
490             In scalar context returns the first value that matches.
491              
492             $value = $trans->via_subheader( $FITS_headers, $keyword );
493              
494 0     0 1 0 In list context returns all the available values in order.
495 0         0  
496 0         0 @values = $trans->via_subheader( $FITS_headers, $keyword );
497              
498             =cut
499              
500             my $self = shift;
501             my $FITS_headers = shift;
502             my $keyword = shift;
503              
504             my @values;
505             if (exists $FITS_headers->{$keyword}
506             && defined $FITS_headers->{$keyword}) {
507              
508             if ( ref( $FITS_headers->{$keyword} ) eq 'ARRAY' ) {
509             @values = @{$FITS_headers->{$keyword}};
510             } else {
511             push (@values,$FITS_headers->{$keyword});
512             }
513             } elsif ( $FITS_headers->{SUBHEADERS}
514             && exists $FITS_headers->{SUBHEADERS}->[0]->{$keyword}) {
515 973     973 1 1245 my @subs = @{$FITS_headers->{SUBHEADERS}};
516 973         1103 for my $s (@subs) {
517 973         1019 if (exists $s->{$keyword} && defined $s->{$keyword}) {
518             push(@values, $s->{$keyword});
519 973         1658 }
520 973 100 100     2893 }
    50 66        
    50 33        
521             } elsif (exists $FITS_headers->{I1}
522             && exists $FITS_headers->{I1}->{$keyword}) {
523 715 50       51464 # need to find out how many In we have
524 0         0 my $i = 1;
  0         0  
525             while (exists $FITS_headers->{"I$i"}) {
526 715         32837 push(@values, $FITS_headers->{"I$i"}->{$keyword});
527             $i++;
528             }
529             }
530 0         0  
  0         0  
531 0         0 return (wantarray ? @values : $values[0] );
532 0 0 0     0 }
533 0         0  
534             =item B<via_subheader_undef_check>
535              
536             Version of via_subheader that removes undefined values from the list before
537             returning the answer. Useful for SCUBA-2 where the first dark may not include
538             the TCS information.
539 0         0  
540 0         0 Same interface as via_subheader.
541 0         0  
542 0         0 =cut
543              
544             my $self = shift;
545             my @values = $self->via_subheader( @_ );
546 973 50       50735  
547             # completely filter out undefs
548             @values = grep { defined $_ } @values;
549             return (wantarray ? @values : $values[0] );
550             }
551              
552             =back
553              
554             =head1 PROTECTED IMPORTS
555              
556             Not all translation methods warrant a full blown inheritance. For
557             cases where one or two translation routines should be imported
558             (e.g. reading DATE-OBS FITS standard headers without importing the
559             additional FITS methods) a special import routine can be used when
560 899     899 1 1507 using the class.
561 899         1514  
562             use Astro::FITS::HdrTrans::FITS qw/ ROTATION /;
563              
564 899         1201 This will load the from_ROTATION and to_ROTATION methods into
  663         1439  
565 899 100       2053 the namespace.
566              
567             =cut
568              
569             my $class = shift;
570              
571             # this is where we are going to install the methods
572             my $callpkg = caller();
573              
574             # Prepend the from_ and to_ prefixes
575             for my $key (@_) {
576             # The key can be fully specified with from_ and to_ already
577             # In that case we do not want to loop over from_ and to_
578             my @directions = qw/ from_ to_ /;
579             if ($key =~ /^from_/ || $key =~ /^to_/) {
580             @directions = ( '' ); # empty prefix
581             }
582              
583             for my $dir (@directions) {
584             my $method = $dir . $key;
585             #print "Importing method $method\n";
586 35     35   95 no strict 'refs';
587              
588             if (!defined *{"$class\::$method"}) {
589 35         86 croak "Method $method is not available for export from class $class";
590             }
591              
592 35         530 # assign it
593             *{"$callpkg\::$method"} = \&{"$class\::$method"};
594             }
595 20         47 }
596 20 50 33     132  
597 0         0 }
598              
599             =head1 WRITING A TRANSLATION CLASS
600 20         33  
601 40         76 In order to create a translation class for a new instrument it is
602             first necessary to work out the different types of translations that
603 52     54   590 are required; whether they are unit mappings (a simple change of
  52         137  
  52         7110  
604             keyword but no change in value), constant mappings (a constant is
605 40 50       61 returned independently of the FITS header), mappings that already
  40         151  
606 0         0 exist in another class or complex mappings that have to be explicitly
607             coded.
608              
609             All translation classes must ultimately inherit from
610 40         55 C<Astro::FITS::HdrTrans::Base>.
  40         368  
  40         93  
611              
612             The first step in creation of a class is to handle the "can this class
613             translate the supplied headers" query that will be requested from
614             the C<Astro::FITS::HdrTrans> package. If the instrument name is present
615             in the standard "INSTRUME" FITS header then this can be achieved simply
616             by writing a C<this_instrument> method in the subclass that will return
617             the name of the instrument that can be translated. If a more complex
618             decision is required it will be necessary to subclass the C<can_translate>
619             method. This takes the headers that are to be translated (either in FITS
620             or generic form since the method is queried for either direction) and
621             returns a boolean indicating whether the class can be used.
622              
623             Once the class can declare it's translation instrument the next
624             step is to write the actual translation methods themselves. If any
625             unit- or constant-mappings are required they can be setup by defining
626             the %UNIT_MAP and %CONST_MAP (the names are unimportant) hashes
627             and calling the base class automated method constructor:
628              
629             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP );
630              
631             If your translations are very similar to an existing set of translations
632             you can inherit from that class instead of C<Astro::FITS::HdrTrans::Base>.
633             Multiple inheritance is supported if, for example, you need to
634             inherit from both the standard FITS translations (eg for DATE-OBS
635             processing) and from a more telescope-specific set of translations.
636              
637             If inheritance causes some erroneous mappings to leak through it is
638             possible to disable a specific mapping by specifying a @NULL_MAP
639             array to the method generation. This is an array of generic keywords.
640              
641             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP,
642             \@NULL_MAP );
643              
644             If a subset of translation methods are required from another class
645             but there is no desire to inherit the full set of methods then it
646             is possible to import specific translation methods from other classes.
647              
648             use Astro::FITS::HdrTrans::FITS qw/ UTSTART UTEND /;
649              
650             would import just the DATE-OBS and DATE-END handling functions from
651             the FITS class. Note that both the from- and to- translations will
652             be imported.
653              
654             At some point you may want to write your own more complex translations.
655             To do this you must write to- and from- methods. The API for all
656             the from_FITS translations is identical:
657              
658             $translation = $class->to_GENERIC_KEYWORD( \%fits_headers );
659              
660             ie given a reference to a hash of FITS headers (which can be
661             a tied C<Astro::FITS::Header> object), return a scalar value which
662             is the translated value.
663              
664             To convert from generic to FITS the interface is:
665              
666             %fits_subset = $class->from_GENERIC_KEYWORD( \%generic_header );
667              
668             ie multiple FITS keywords and values can be returned since in some
669             cases a single generic keyword is obtained by combining information
670             from multiple FITS headers.
671              
672             Finally, if this translation module is to be part of the
673             C<Astro::FITS::HdrTrans> distribution the default list of translation
674             classes must be updated in C<Astro::FITS::HdrTrans>. If this is to be
675             a runtime plugin, then the list of classes can be expanded at
676             runtime. For example, it should be possible for
677             C<Astro::FITS::HdrTrans::MyNewInst> to automatically append itself to
678             the list of known classes if the module is explicitly loaded by the
679             user (rather than dynamically loaded to test the headers).
680              
681             Some generic keywords actually return scalar objects. Any new instruments
682             must consistently return compatible objects. For example, UTDATE,
683             UTSTART and UTEND return (currently) Time::Piece objects.
684              
685             =head1 SEE ALSO
686              
687             C<Astro::FITS::HdrTrans>
688              
689             =head1 AUTHOR
690              
691             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>
692              
693             =head1 COPYRIGHT
694              
695             Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
696             All Rights Reserved.
697              
698             This program is free software; you can redistribute it and/or modify it under
699             the terms of the GNU General Public License as published by the Free Software
700             Foundation; either version 2 of the License, or (at your option) any later
701             version.
702              
703             This program is distributed in the hope that it will be useful,but WITHOUT ANY
704             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
705             PARTICULAR PURPOSE. See the GNU General Public License for more details.
706              
707             You should have received a copy of the GNU General Public License along with
708             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
709             Place,Suite 330, Boston, MA 02111-1307, USA
710              
711             =cut
712              
713             1;