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