File Coverage

blib/lib/Astro/FITS/HdrTrans/LCOFLOYDS.pm
Criterion Covered Total %
statement 15 108 13.8
branch 0 42 0.0
condition 0 9 0.0
subroutine 6 17 35.2
pod 11 12 91.6
total 32 188 17.0


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