File Coverage

blib/lib/Astro/FITS/HdrTrans/NACO.pm
Criterion Covered Total %
statement 18 152 11.8
branch 0 98 0.0
condition 0 63 0.0
subroutine 7 17 41.1
pod 1 11 9.0
total 26 341 7.6


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Astro::FITS::HdrTrans::NACO - ESO NACO translations
5              
6             =head1 SYNOPSIS
7              
8             use Astro::FITS::HdrTrans::NACO;
9              
10             %gen = Astro::FITS::HdrTrans::NACO->translate_from_FITS( %hdr );
11              
12             =head1 DESCRIPTION
13              
14             This class provides a generic set of translations that are specific to
15             the NACO camera of the European Southern Observatory.
16              
17             =cut
18              
19             use 5.006;
20 10     10   7973315 use warnings;
  10         39  
21 10     10   44 use strict;
  10         19  
  10         298  
22 10     10   48 use Carp;
  10         34  
  10         187  
23 10     10   43  
  10         19  
  10         780  
24             # Inherit from ESO
25             use base qw/ Astro::FITS::HdrTrans::ESO /;
26 10     10   55  
  10         14  
  10         1424  
27             use vars qw/ $VERSION /;
28 10     10   73  
  10         19  
  10         13080  
29             $VERSION = "1.65";
30              
31             # for a constant mapping, there is no FITS header, just a generic
32             # header that is constant
33             my %CONST_MAP = (
34             POLARIMETRY => 0,
35             );
36              
37             # NULL mappings used to override base class implementations
38             my @NULL_MAP = qw/ /;
39              
40             # unit mapping implies that the value propogates directly
41             # to the output with only a keyword name change
42              
43             my %UNIT_MAP = (
44             );
45              
46              
47             # Create the translation methods
48             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP, \@NULL_MAP );
49              
50             =head1 METHODS
51              
52             =over 4
53              
54             =item B<this_instrument>
55              
56             The name of the instrument required to match (case insensitively)
57             against the INSTRUME/INSTRUMENT keyword to allow this class to
58             translate the specified headers. Called by the default
59             C<can_translate> method.
60              
61             $inst = $class->this_instrument();
62              
63             Returns "NAOS+CONICA".
64              
65             =cut
66              
67             return "NAOS+CONICA";
68             }
69 20     20 1 49  
70             =back
71              
72             =head1 COMPLEX CONVERSIONS
73              
74             =over 4
75              
76             =cut
77              
78             my $self = shift;
79             my $FITS_headers = shift;
80             my $scale;
81 0     0 0   my $scale_def = 0.0271;
82 0           if ( exists ( $FITS_headers->{CDELT2} ) ) {
83 0           $scale = $FITS_headers->{CDELT2};
84 0           } elsif ( exists ( $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} ) ) {
85 0 0         $scale = $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} / 3600.0;
    0          
86 0           }
87             $scale = defined( $scale ) ? $scale: $scale_def;
88 0           return $scale;
89             }
90 0 0          
91 0           # If the telescope ofset exists in arcsec, then use it. Otherwise
92             # convert the Cartesian offsets to equatorial offsets.
93             my $self = shift;
94             my $FITS_headers = shift;
95             my $decoffset = 0.0;
96             if ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETD"} ) {
97 0     0 0   $decoffset = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETD"};
98 0            
99 0           } elsif ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} &&
100 0 0 0       exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} ) {
    0          
101 0            
102             my $pixscale = 0.0271;
103             if ( exists $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} ) {
104             $pixscale = $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"};
105             }
106 0            
107 0 0         # Sometimes the first cumulative offsets are non-zero contrary to the
108 0           # documentation.
109             my $expno = 1;
110             if ( exists $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"} ) {
111             $expno = $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"};
112             }
113 0           my ( $x_as, $y_as );
114 0 0         if ( $expno == 1 ) {
115 0           $x_as = 0.0;
116             $y_as = 0.0;
117 0           } else {
118 0 0         $x_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} * $pixscale;
119 0           $y_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} * $pixscale;
120 0           }
121              
122 0           # Define degrees to radians conversion and obtain the rotation angle.
123 0           my $dtor = atan2( 1, 1 ) / 45.0;
124              
125             my $rotangle = $self->rotation($FITS_headers);
126             my $cosrot = cos( $rotangle * $dtor );
127 0           my $sinrot = sin( $rotangle * $dtor );
128              
129 0           # Apply the rotation matrix to obtain the equatorial pixel offset.
130 0           $decoffset = -$x_as * $sinrot + $y_as * $cosrot;
131 0           }
132              
133             # The sense is reversed compared with UKIRT, as these measure the
134 0           # place on the sky, not the motion of the telescope.
135             return -1.0 * $decoffset;
136             }
137              
138             # Derive the translation between observing template and recipe name.
139 0           my $self = shift;
140             my $FITS_headers = shift;
141             my $recipe = "QUICK_LOOK";
142              
143             # Obtain the observing template. These are equivalent
144 0     0 0   # to the UKIRT OT science programmes and their tied DR recipes.
145 0           # However, there are some wrinkles and variations to be tested.
146 0           my $template = $FITS_headers->{"HIERARCH.ESO.TPL.ID"};
147             my $seq = $FITS_headers->{"HIERARCH.ESO.TPL.PRESEQ"};
148              
149             if ( $template =~ /_img_obs_AutoJitter/ ||
150             $template =~ /_img_obs_GenericOffset/ ) {
151 0           $recipe = "JITTER_SELF_FLAT";
152 0            
153             } elsif ( $template =~ /_img_cal_StandardStar/ ||
154 0 0 0       $template =~ /_img_cal_StandardStarOff/ ||
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
      0        
155             $template =~ /_img_tec_Zp/ ||
156 0           $template =~ /_img_tec_ZpNoChop/ ||
157             $seq =~ /_img_cal_StandardStar/ ||
158             $seq =~ /_img_cal_StandardStarOff/ ) {
159             $recipe = "JITTER_SELF_FLAT_APHOT";
160              
161             } elsif ( $template =~ /_img_obs_AutoJitterOffset/ ||
162             $template =~ /_img_obs_FixedSkyOffset/ ) {
163             $recipe = "CHOP_SKY_JITTER";
164 0            
165             # The following two perhaps should be using NOD_CHOP and a variant of
166             # NOD_CHOP_APHOT to cope with the three source images (central double
167             # flux) rather than four.
168 0           } elsif ( $template =~ /_img_obs_AutoChopNod/ ||
169             $seq =~ /_img_obs_AutoChopNod/ ) {
170             $recipe = "NOD_SELF_FLAT_NO_MASK";
171              
172             } elsif ( $template =~ /_img_cal_ChopStandardStar/ ) {
173             $recipe = "NOD_SELF_FLAT_NO_MASK_APHOT";
174              
175 0           } elsif ( $template =~ /_cal_Darks/ ||
176             $seq =~ /_cal_Darks/ ) {
177             $recipe = "REDUCE_DARK";
178 0            
179             } elsif ( $template =~ /_img_cal_TwFlats/ ||
180             $template =~ /_img_cal_SkyFlats/ ) {
181             $recipe = "SKY_FLAT_MASKED";
182 0            
183             } elsif ( $template =~ /_img_cal_LampFlats/ ) {
184             $recipe = "LAMP_FLAT";
185              
186 0           # Imaging spectroscopy. There appears to be no distinction
187             # for flats from target, hence no division into POL_JITTER and
188             # SKY_FLAT_POL.
189 0           } elsif ( $template =~ /_pol_obs_GenericOffset/ ||
190             $template =~ /_pol_cal_StandardStar/ ) {
191             $recipe = "POL_JITTER";
192              
193             } elsif ( $template =~ /_pol_obs_AutoChopNod/ ||
194             $template =~ /_pol_cal_ChopStandardStar/ ) {
195             $recipe = "POL_NOD_CHOP";
196 0            
197             } elsif ( $template =~ /_pol_cal_LampFlats/ ) {
198             $recipe = "POL_JITTER";
199              
200 0           # Spectroscopy. EXTENDED_SOURCE may be more appropriate for
201             # the NACO_spec_obs_GenericOffset template.
202             } elsif ( $template =~ /_spec_obs_AutoNodOnSlit/ ||
203 0           $template =~ /_spec_obs_GenericOffset/ ||
204             $template =~ /_spec_obs_AutoChopNod/ ) {
205             $recipe = "POINT_SOURCE";
206              
207             } elsif ( $template =~ /_spec_cal_StandardStar/ ||
208             $template =~ /_spec_cal_StandardStarNod/ ||
209             $template =~ /_spec_cal_AutoNodOnSlit/ ) {
210 0           $recipe = "STANDARD_STAR";
211              
212             } elsif ( $template =~ /_spec_cal_NightCalib/ ) {
213             $recipe = "REDUCE_SINGLE_FRAME";
214              
215 0           } elsif ( $template =~ /_spec_cal_Arcs/ ||
216             $seq =~ /_spec_cal_Arcs/ ) {
217             $recipe = "REDUCE_ARC";
218 0            
219             } elsif ( $template =~ /_spec_cal_LampFlats/ ) {
220             $recipe = "LAMP_FLAT";
221             }
222 0           return $recipe;
223             }
224              
225 0            
226             # Filters appear to be in wheels 4 to 6. It appears the filter
227 0           # in just one of the three.
228             my $self = shift;
229             my $FITS_headers = shift;
230             my $filter = "empty";
231              
232             my $id = 4;
233             while ( $filter eq "empty" && $id < 7 ) {
234 0     0 0   if ( exists $FITS_headers->{"HIERARCH.ESO.INS.OPTI${id}.NAME"} ) {
235 0           $filter = $FITS_headers->{"HIERARCH.ESO.INS.OPTI${id}.NAME"};
236 0           }
237             $id++;
238 0           }
239 0   0       return $filter;
240 0 0         }
241 0            
242             # Fixed value for the gain, as that's all the documentation gives.
243 0           # the readout mode.
244             10;
245 0           }
246              
247             # Using Table 10 of the NACO USer's Guide.
248             my $self = shift;
249             my $FITS_headers = shift;
250             my $dispersion = 0.0;
251 0     0 0   if ( exists $FITS_headers->{CDELT1} ) {
252             $dispersion = $FITS_headers->{CDELT1};
253             } else {
254             if ( exists $FITS_headers->{"HIERARCH.ESO.INS.GRAT.NAME"} &&
255             exists $FITS_headers->{"HIERARCH.ESO.OPTI7.NAME"} ) {
256 0     0 0   my $order = $FITS_headers->{"HIERARCH.ESO.INS.GRAT.ORDER"};
257 0           my $camera = $FITS_headers->{"HIERARCH.ESO.OPTI7.NAME"};
258 0            
259 0 0         if ( $camera eq "S54" ) {
260 0           if ( $order == 1 ) {
261             $dispersion = 1.98e-3;
262 0 0 0       } elsif ( $order == 2 ) {
263             $dispersion = 6.8e-4;
264 0           } elsif ( $order == 3 ) {
265 0           $dispersion = 9.7e-4;
266             }
267 0 0          
    0          
    0          
268 0 0         } elsif ( $camera eq "L54" ) {
    0          
    0          
269 0           $dispersion = 3.20e-3;
270              
271 0           } elsif ( $camera eq "S27" ) {
272             if ( $order == 1 ) {
273 0           $dispersion = 9.5e-4;
274             } elsif ( $order == 2 ) {
275             $dispersion = 5.0e-4;
276             }
277 0           }
278             }
279             }
280 0 0         return $dispersion;
    0          
281 0           }
282              
283 0           my $self = shift;
284             my $FITS_headers = shift;
285             my $scale;
286             my $scale_def = -0.0271;
287             if ( exists ( $FITS_headers->{CDELT1} ) ) {
288 0           $scale = $FITS_headers->{CDELT1};
289             } elsif ( exists ( $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} ) ) {
290             $scale = - $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} / 3600.0;
291             }
292 0     0 0   $scale = defined( $scale ) ? $scale: $scale_def;
293 0           return $scale;
294 0           }
295 0            
296 0 0         # If the telescope offset exists in arcsec, then use it. Otherwise
    0          
297 0           # convert the Cartesian offsets to equatorial offsets.
298             my $self = shift;
299 0           my $FITS_headers = shift;
300             my $raoffset = 0.0;
301 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETA"} ) {
302 0           $raoffset = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETA"};
303              
304             } elsif ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} &&
305             exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} ) {
306              
307             my $pixscale = 0.0271;
308 0     0 0   if ( exists $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} ) {
309 0           $pixscale = $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"};
310 0           }
311 0 0 0        
    0          
312 0           # Sometimes the first cumulative offsets are non-zero contrary to the
313             # documentation.
314             my $expno = 1;
315             if ( exists $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"} ) {
316             $expno = $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"};
317 0           }
318 0 0         my ( $x_as, $y_as );
319 0           if ( $expno == 1 ) {
320             $x_as = 0.0;
321             $y_as = 0.0;
322             } else {
323             $x_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} * $pixscale;
324 0           $y_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} * $pixscale;
325 0 0         }
326 0            
327             # Define degrees to radians conversion and obtain the rotation angle.
328 0           my $dtor = atan2( 1, 1 ) / 45.0;
329 0 0          
330 0           my $rotangle = $self->rotation($FITS_headers);
331 0           my $cosrot = cos( $rotangle * $dtor );
332             my $sinrot = sin( $rotangle * $dtor );
333 0            
334 0           # Apply the rotation matrix to obtain the equatorial pixel offset.
335             $raoffset = -$x_as * $cosrot + $y_as * $sinrot;
336             }
337              
338 0           # The sense is reversed compared with UKIRT, as these measure the
339             # place on the sky, not the motion of the telescope.
340 0           return -1.0 * $raoffset;
341 0           }
342 0            
343             # Just translate to shorter strings for ease and to fit within the
344             # night log.
345 0           my $self = shift;
346             my $FITS_headers = shift;
347             my $spd_gain = "HighSens";
348             my $detector_mode = exists( $FITS_headers->{"HIERARCH.ESO.DET.MODE.NAME"} ) ?
349             $FITS_headers->{"HIERARCH.ESO.DET.MODE.NAME"} : $spd_gain;
350 0           if ( $detector_mode eq "HighSensitivity" ) {
351             $spd_gain = "HighSens";
352             } elsif ( $detector_mode eq "HighDynamic" ) {
353             $spd_gain = "HighDyn";
354             } elsif ( $detector_mode eq "HighBackground" ) {
355             $spd_gain = "HighBack";
356 0     0 0   }
357 0           return $spd_gain;
358 0           }
359              
360 0 0         # Translate to the SLALIB name for reference frame in spectroscopy.
361 0 0         my $self = shift;
    0          
    0          
362 0           my $FITS_headers = shift;
363             my $telescope = "VLT4";
364 0           if ( exists $FITS_headers->{TELESCOP} ) {
365             my $scope = $FITS_headers->{TELESCOP};
366 0           if ( defined( $scope ) ) {
367             $telescope = $scope;
368 0           $telescope =~ s/ESO-//;
369             $telescope =~ s/-U//g;
370             }
371             }
372             return $telescope;
373 0     0 0   }
374 0            
375 0           =back
376 0 0          
377 0           =head1 SEE ALSO
378 0 0          
379 0           C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::UKIRT>.
380 0            
381 0           =head1 AUTHOR
382              
383             Malcolm J. Currie E<lt>mjc@star.rl.ac.ukE<gt>
384 0           Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
385             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>.
386              
387             =head1 COPYRIGHT
388              
389             Copyright (C) 2008 Science and Technology Facilities Council.
390             Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
391             All Rights Reserved.
392              
393             This program is free software; you can redistribute it and/or modify it under
394             the terms of the GNU General Public License as published by the Free Software
395             Foundation; either Version 2 of the License, or (at your option) any later
396             version.
397              
398             This program is distributed in the hope that it will be useful,but WITHOUT ANY
399             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
400             PARTICULAR PURPOSE. See the GNU General Public License for more details.
401              
402             You should have received a copy of the GNU General Public License along with
403             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
404             Place, Suite 330, Boston, MA 02111-1307, USA.
405              
406             =cut
407              
408             1;