File Coverage

blib/lib/Astro/FITS/HdrTrans/LCOFLOYDS.pm
Criterion Covered Total %
statement 18 111 16.2
branch 0 42 0.0
condition 0 9 0.0
subroutine 7 18 38.8
pod 11 12 91.6
total 36 192 18.7


line stmt bran cond sub pod time code
1             # -*-perl-*-
2              
3             package Astro::FITS::HdrTrans::LCOFLOYDS;
4              
5             =head1 NAME
6              
7             Astro::FITS::HdrTrans::LCOFLOYDS - LCO 2.0m FLOYDS translations
8              
9             =head1 SYNOPSIS
10              
11             use Astro::FITS::HdrTrans::LCOFLOYDS;
12              
13             %gen = Astro::FITS::HdrTrans::LCOFLOYDS->translate_from_FITS( %hdr );
14              
15             =head1 DESCRIPTION
16              
17             This class provides a generic set of translations that are specific to
18             2.0m FLOYDSs at LCO.
19              
20             =cut
21              
22 10     10   13464229 use 5.006;
  10         88  
23 10     10   60 use warnings;
  10         31  
  10         355  
24 10     10   55 use strict;
  10         38  
  10         247  
25 10     10   56 use Carp;
  10         31  
  10         837  
26              
27             # Inherit from LCO base class.
28 10     10   61 use base qw/ Astro::FITS::HdrTrans::LCO /;
  10         22  
  10         2239  
29              
30 10     10   85 use vars qw/ $VERSION /;
  10         24  
  10         13401  
31              
32             $VERSION = "1.63";
33              
34             # for a constant mapping, there is no FITS header, just a generic
35             # header that is constant
36              
37             # NULL mappings used to override base-class implementations.
38             my @NULL_MAP = qw/ /;
39              
40             my %CONST_MAP = ( OBSERVATION_MODE => 'spectroscopy',
41             GRATING_NAME => 'FLOYDS GRATING',
42             GRATING_ORDER => 1,
43             GRATING_DISPERSION => 1.73/10000.0,
44             GRATING_WAVELENGTH => 0.556,
45             NSCAN_POSITIONS => 1,
46             NUMBER_OF_READS => 1,
47             SCAN_INCREMENT => 1,
48             );
49              
50             my %UNIT_MAP = (
51             SLIT_NAME => "APERTURE",
52             SLIT_WIDTH => "APERWID",
53             X_DIM => "NAXIS1",
54             Y_DIM => "NAXIS2",
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 "LCOFLOYDS".
75              
76             =cut
77              
78             sub this_instrument {
79 20     20 1 85 return qr/(^en05)|(^en06)/i
80              
81             }
82              
83             =back
84              
85             =head1 COMPLEX CONVERSIONS
86              
87             These methods are more complicated than a simple mapping. We have to
88             provide both from- and to-FITS conversions All these routines are
89             methods and the to_ routines all take a reference to a hash and return
90             the translated value (a many-to-one mapping) The from_ methods take a
91             reference to a generic hash and return a translated hash (sometimes
92             these are many-to-many)
93              
94             =over 4
95              
96             =cut
97              
98             =item B<to_DEC_SCALE>
99              
100             Sets the declination scale in arcseconds per pixel. The C<PIXSCALE>
101             is used when it's defined. Otherwise it returns a default value of 0.2320
102             arcsec/pixel, multiplied by C<YBINNING> assuming this is defined
103              
104             =cut
105              
106             sub to_DEC_SCALE {
107 0     0 1   my $self = shift;
108 0           my $FITS_headers = shift;
109 0           my $decscale = 0.3860;
110              
111             # Assumes either x-y scales the same or the y corresponds to
112             # declination.
113 0           my $ccdscale = $self->via_subheader( $FITS_headers, "PIXSCALE" );
114 0 0         if ( defined $ccdscale ) {
115 0           $decscale = $ccdscale;
116             } else {
117 0           my $ybinning = $self->via_subheader( $FITS_headers, "YBINNING" );
118 0 0         if ( defined $ybinning ) {
119 0           $decscale = $decscale * $ybinning;
120             }
121             }
122 0           return $decscale;
123             }
124              
125             =item B<to_DEC_TELESCOPE_OFFSET>
126              
127             Sets the declination telescope offset in arcseconds. It uses the
128             C<CAT-DEC> and C<DEC> keywords to derive the offset, and if either
129             does not exist, it returns a default of 0.0.
130              
131             =cut
132              
133             sub to_DEC_TELESCOPE_OFFSET {
134 0     0 1   my $self = shift;
135 0           my $FITS_headers = shift;
136 0           my $decoffset = 0.0;
137 0 0 0       if ( exists $FITS_headers->{"CAT-DEC"} && exists $FITS_headers->{DEC} ) {
138              
139             # Obtain the reference and telescope declinations positions measured in degrees.
140 0           my $refdec = $self->dms_to_degrees( $FITS_headers->{"CAT-DEC"} );
141 0           my $dec = $self->dms_to_degrees( $FITS_headers->{DEC} );
142              
143             # Find the offsets between the positions in arcseconds on the sky.
144 0           $decoffset = 3600.0 * ( $dec - $refdec );
145             }
146              
147             # The sense is reversed compared with UKIRT, as these measure the
148             # places on the sky, not the motion of the telescope.
149 0           return -1.0 * $decoffset;
150             }
151              
152             =item B<to_DR_RECIPE>
153              
154             Returns the data-reduction recipe name. The selection depends on the
155             values of the C<OBJECT> and C<OBSTYPE> keywords. The default is
156             "QUICK_LOOK". A dark returns "REDUCE_DARK", and an object's recipe is
157             "JITTER_SELF_FLAT".
158              
159             =cut
160              
161             sub to_DR_RECIPE {
162 0     0 1   my $self = shift;
163 0           my $FITS_headers = shift;
164 0           my $recipe = "QUICK_LOOK";
165              
166 0 0         if ( exists $FITS_headers->{OBSTYPE} ) {
167 0 0         if ( $FITS_headers->{OBSTYPE} =~ /ARC/i ) {
    0          
    0          
    0          
    0          
    0          
168 0           $recipe = "REDUCE_ARC";
169             } elsif ( $FITS_headers->{OBSTYPE} =~ /BIAS/i ) {
170 0           $recipe = "REDUCE_BIAS";
171             } elsif ( $FITS_headers->{OBSTYPE} =~ /DARK/i ) {
172 0           $recipe = "REDUCE_DARK";
173             } elsif ( $FITS_headers->{OBSTYPE} =~ /LAMPFLAT/i ) {
174 0           $recipe = "REDUCE_FLAT";
175             } elsif ( $FITS_headers->{OBSTYPE} =~ /EXPOSE/i ) {
176             # $recipe = "JITTER_SELF_FLAT";
177 0           $recipe = "POINT_SOURCE_NOSTD";
178             } elsif ( $FITS_headers->{OBSTYPE} =~ /STANDARD/i ) {
179 0           $recipe = "STANDARD_STAR";
180             }
181             }
182              
183 0           return $recipe;
184             }
185              
186             =item B<to_RA_SCALE>
187              
188             Sets the RA scale in arcseconds per pixel. The C<PIXSCALE>
189             is used when it's defined. Otherwise it returns a default value of 0.2320
190             arcsec/pixel, multiplied by C<XBINNING> assuming this is defined (1.0 otherwise)
191              
192             =cut
193              
194             sub to_RA_SCALE {
195 0     0 1   my $self = shift;
196 0           my $FITS_headers = shift;
197 0           my $rascale = 0.3860;
198              
199             # Assumes either x-y scales the same or the x corresponds to
200             # ra.
201 0           my $ccdscale = $self->via_subheader( $FITS_headers, "PIXSCALE" );
202 0 0         if ( defined $ccdscale ) {
203 0           $rascale = $ccdscale;
204             } else {
205 0           my $xbinning = $self->via_subheader( $FITS_headers, "XBINNING" );
206 0 0         if ( defined $xbinning ) {
207 0           $rascale = $rascale * $xbinning;
208             }
209             }
210 0           return $rascale;
211             }
212              
213              
214             =item B<to_RA_TELESCOPE_OFFSET>
215              
216             Sets the right-ascension telescope offset in arcseconds. It uses the
217             C<CAT-RA>, C<RA>, C<CAT-DEC> keywords to derive the offset, and if any
218             of these keywords does not exist, it returns a default of 0.0.
219              
220             =cut
221              
222             sub to_RA_TELESCOPE_OFFSET {
223 0     0 1   my $self = shift;
224 0           my $FITS_headers = shift;
225 0           my $raoffset = 0.0;
226              
227 0 0 0       if ( exists $FITS_headers->{"CAT-DEC"} &&
      0        
228             exists $FITS_headers->{"CAT-RA"} && exists $FITS_headers->{RA} ) {
229              
230             # Obtain the reference and telescope sky positions measured in degrees.
231 0           my $refra = $self->hms_to_degrees( $FITS_headers->{"CAT-RA"} );
232 0           my $ra = $self->hms_to_degrees( $FITS_headers->{RA} );
233 0           my $refdec = $self->dms_to_degrees( $FITS_headers->{"CAT-DEC"} );
234              
235             # Find the offset between the positions in arcseconds on the sky.
236 0           $raoffset = 3600.0 * ( $ra - $refra ) * $self->cosdeg( $refdec );
237             }
238              
239             # The sense is reversed compared with UKIRT, as these measure the
240             # place son the sky, not the motion of the telescope.
241 0           return -1.0 * $raoffset;
242             }
243              
244             =item B<to_SLIT_ANGLE>
245              
246             Returns the slit PA, trapping UNKNOWN values and setting them to -999 (could
247             in principle be recalculated from HA, Dec and Latitude via some SLALIBing...
248              
249             =cut
250              
251             sub to_SLIT_ANGLE {
252 0     0 1   my $self = shift;
253 0           my $FITS_headers = shift;
254 0           my $slit_angle = -999.0;
255 0 0         if ( exists $FITS_headers->{APERPA} ) {
256 0           my $slit_pa = $FITS_headers->{APERPA};
257 0 0         if ( $slit_pa !~ /UNKNOWN/i ) {
258 0           $slit_angle = $slit_pa;
259             }
260             }
261 0           return $slit_angle;
262             }
263              
264              
265             =item B<to_X_LOWER_BOUND>
266              
267             Returns the lower bound along the X-axis of the area of the detector
268             as a pixel index.
269              
270             =cut
271              
272             sub to_X_LOWER_BOUND {
273 0     0 1   my $self = shift;
274 0           my $FITS_headers = shift;
275 0           my @bounds = $self->getbounds( $FITS_headers );
276 0           return $bounds[ 0 ];
277             }
278              
279             =item B<to_X_UPPER_BOUND>
280              
281             Returns the upper bound along the X-axis of the area of the detector
282             as a pixel index.
283              
284             =cut
285              
286             sub to_X_UPPER_BOUND {
287 0     0 1   my $self = shift;
288 0           my $FITS_headers = shift;
289 0           my @bounds = $self->getbounds( $FITS_headers );
290 0           return $bounds[ 1 ];
291             }
292              
293             =item B<to_Y_LOWER_BOUND>
294              
295             Returns the lower bound along the Y-axis of the area of the detector
296             as a pixel index.
297              
298             =cut
299              
300             sub to_Y_LOWER_BOUND {
301 0     0 1   my $self = shift;
302 0           my $FITS_headers = shift;
303 0           my @bounds = $self->getbounds( $FITS_headers );
304 0           return $bounds[ 2 ];
305             }
306              
307              
308             =item B<to_Y_UPPER_BOUND>
309              
310             Returns the upper bound along the Y-axis of the area of the detector
311             as a pixel index.
312              
313             =cut
314              
315             sub to_Y_UPPER_BOUND {
316 0     0 1   my $self = shift;
317 0           my $FITS_headers = shift;
318 0           my @bounds = $self->getbounds( $FITS_headers );
319 0           return $bounds[ 3 ];
320             }
321              
322             # Supplementary methods for the translations
323             # ------------------------------------------
324              
325             # Obtain the detector bounds from a section in [xl:xu,yl:yu] syntax.
326             # If the TRIMSEC header is absent, use a default which corresponds
327             # to the useful part of the array (minus bias strips).
328             sub getbounds{
329 0     0 0   my $self = shift;
330 0           my $FITS_headers = shift;
331 0           my @bounds = ( 1, 2048, 1, 512 );
332 0 0         if ( exists $FITS_headers->{CCDSUM} ) {
333 0           my $binning = $FITS_headers->{CCDSUM};
334 0 0         if ( $binning eq '2 2' ) {
335 0           @bounds = ( 1, 1024, 1, 256 );
336             }
337             }
338 0 0         if ( exists $FITS_headers->{TRIMSEC} ) {
339 0           my $section = $FITS_headers->{TRIMSEC};
340 0 0         if ( $section !~ /UNKNOWN/i ) {
341 0           $section =~ s/\[//;
342 0           $section =~ s/\]//;
343 0           $section =~ s/,/:/g;
344 0           my @newbounds = split( /:/, $section );
345 0 0         if (@newbounds == grep { $_ == 0 } @newbounds) {
  0            
346 0           print "ERR: TRIMSEC all 0\n";
347             } else {
348 0 0         if ( $FITS_headers->{INSTRUME} !~ /^en0/i ) {
349             # Unless this is any data (which has a bad TRIMSEC), update bounds array
350 0           @bounds = @newbounds;
351             }
352             }
353             }
354             }
355             # print("DBG: Bounds=@bounds\n");
356 0           return @bounds;
357             }
358              
359             =back
360              
361             =head1 SEE ALSO
362              
363             C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::LCO>.
364              
365             =head1 AUTHOR
366              
367             Tim Lister E<lt>tlister@lcogt.netE<gt>
368              
369             =head1 COPYRIGHT
370              
371             =cut
372              
373             1;