File Coverage

blib/lib/Astro/FITS/HdrTrans/ISAAC.pm
Criterion Covered Total %
statement 18 159 11.3
branch 0 112 0.0
condition 0 69 0.0
subroutine 7 15 46.6
pod 2 9 22.2
total 27 364 7.4


line stmt bran cond sub pod time code
1             package Astro::FITS::HdrTrans::ISAAC;
2              
3             =head1 NAME
4              
5             Astro::FITS::HdrTrans::ISAAC - ESO ISAAC translations
6              
7             =head1 SYNOPSIS
8              
9             use Astro::FITS::HdrTrans::ISAAC;
10              
11             %gen = Astro::FITS::HdrTrans::ISAAC->translate_from_FITS( %hdr );
12              
13             =head1 DESCRIPTION
14              
15             This class provides a generic set of translations that are specific to
16             the ISAAC camera of the European Southern Observatory.
17              
18             =cut
19              
20 10     10   11640529 use 5.006;
  10         40  
21 10     10   71 use warnings;
  10         38  
  10         379  
22 10     10   66 use strict;
  10         31  
  10         214  
23 10     10   82 use Carp;
  10         25  
  10         880  
24              
25             # Inherit from ESO
26 10     10   68 use base qw/ Astro::FITS::HdrTrans::ESO /;
  10         19  
  10         1712  
27              
28 10     10   86 use vars qw/ $VERSION /;
  10         25  
  10         17660  
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 "ISAAC".
65              
66             =cut
67              
68             sub this_instrument {
69 20     20 1 60 return "ISAAC";
70             }
71              
72             =back
73              
74             =head1 COMPLEX CONVERSIONS
75              
76             =over 4
77              
78             =item B<to_DEC_TELESCOPE_OFFSET>
79              
80             If the telescope ofset exists in arcsec, then use it. Otherwise
81             convert the Cartesian offsets to equatorial offsets.
82              
83             =cut
84              
85             sub to_DEC_TELESCOPE_OFFSET {
86 0     0 1   my $self = shift;
87 0           my $FITS_headers = shift;
88 0           my $decoffset = 0.0;
89 0 0 0       if ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETD"} ) {
    0          
90 0           $decoffset = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETD"};
91              
92             } elsif ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} &&
93             exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} ) {
94              
95 0           my $pixscale = 0.148;
96 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} ) {
97 0           $pixscale = $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"};
98             }
99              
100             # Sometimes the first imaging cumulative offsets are non-zero contrary
101             # to the documentation.
102 0           my $expno = 1;
103 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"} ) {
104 0           $expno = $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"};
105             }
106 0           my ( $x_as, $y_as );
107 0           my $mode = uc( $self->get_instrument_mode($FITS_headers) );
108 0 0 0       if ( $expno == 1 && ( $mode eq "IMAGE" || $mode eq "POLARIMETRY" ) ) {
      0        
109 0           $x_as = 0.0;
110 0           $y_as = 0.0;
111             } else {
112 0           $x_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} * $pixscale;
113 0           $y_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} * $pixscale;
114             }
115              
116             # Define degrees to radians conversion and obtain the rotation angle.
117 0           my $dtor = atan2( 1, 1 ) / 45.0;
118              
119 0           my $rotangle = $self->rotation($FITS_headers);
120 0           my $cosrot = cos( $rotangle * $dtor );
121 0           my $sinrot = sin( $rotangle * $dtor );
122              
123             # Apply the rotation matrix to obtain the equatorial pixel offset.
124 0           $decoffset = -$x_as * $sinrot + $y_as * $cosrot;
125             }
126              
127             # The sense is reversed compared with UKIRT, as these measure the
128             # place on the sky, not the motion of the telescope.
129 0           return -1.0 * $decoffset;
130             }
131              
132             # Filter positions 1 and 2 used for SW and 3 & 4 for LW.
133             sub to_FILTER {
134 0     0 0   my $self = shift;
135 0           my $FITS_headers = shift;
136 0           my $filter = "Ks";
137 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.FILT1.ID"} ) {
    0          
138 0           $filter = $FITS_headers->{"HIERARCH.ESO.INS.FILT1.ID"};
139             } elsif ( exists $FITS_headers->{"HIERARCH.ESO.INS.FILT3.ID"} ) {
140 0           $filter = $FITS_headers->{"HIERARCH.ESO.INS.FILT3.ID"};
141             }
142 0           return $filter;
143             }
144              
145             # Fixed values for the gain depend on the camera (SW or LW), and for LW
146             # the readout mode.
147             sub to_GAIN {
148 0     0 0   my $self = shift;
149 0           my $FITS_headers = shift;
150 0           my $gain = 4.6;
151 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.MODE"} ) {
152 0 0         if ( $FITS_headers->{"HIERARCH.ESO.INS.MODE"} =~ /SW/ ) {
153 0           $gain = 4.6;
154             } else {
155 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.DET.MODE.NAME"} ) {
156 0 0         if ( $FITS_headers->{"HIERARCH.ESO.DET.MODE.NAME"} =~ /LowBias/ ) {
157 0           $gain = 8.7;
158             } else {
159 0           $gain = 7.8;
160             }
161             }
162             }
163             }
164 0           return $gain;
165             }
166              
167             sub to_GRATING_DISPERSION {
168 0     0 0   my $self = shift;
169 0           my $FITS_headers = shift;
170 0           my $dispersion = 0.0;
171             # if ( exists $FITS_headers->{CDELT1} ) {
172             # $dispersion = $FITS_headers->{CDELT1};
173             # } else {
174 0 0 0       if ( exists $FITS_headers->{"HIERARCH.ESO.INS.GRAT.NAME"} &&
175             exists $FITS_headers->{"HIERARCH.ESO.INS.GRAT.ORDER"} ) {
176 0           my $order = $FITS_headers->{"HIERARCH.ESO.INS.GRAT.ORDER"};
177 0 0         if ( $FITS_headers->{"HIERARCH.ESO.INS.GRAT.NAME"} eq "LR" ) {
    0          
178 0 0         if ( $order == 6 ) {
    0          
    0          
    0          
    0          
    0          
179 0           $dispersion = 2.36e-4;
180             } elsif ( $order == 5 ) {
181 0           $dispersion = 2.83e-4;
182             } elsif ( $order == 4 ) {
183 0           $dispersion = 3.54e-4;
184             } elsif ( $order == 3 ) {
185 0           $dispersion = 4.72e-4;
186             } elsif ( $order == 2 ) {
187 0           $dispersion = 7.09e-4;
188             } elsif ( $order == 1 ) {
189 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.FILT1.ID"} ) {
190 0           my $filter = $FITS_headers->{"HIERARCH.ESO.INS.FILT1.ID"};
191 0 0         if ( $filter =~/SL/ ) {
192 0           $dispersion = 1.412e-3;
193             } else {
194 0           $dispersion = 1.45e-3;
195             }
196             } else {
197 0           $dispersion = 1.41e-3;
198             }
199             }
200              
201             # Medium dispersion
202             } elsif ( $FITS_headers->{"HIERARCH.ESO.INS.GRAT.NAME"} eq "MR" ) {
203 0 0         if ( $order == 6 ) {
    0          
    0          
    0          
    0          
    0          
204 0           $dispersion = 3.7e-5;
205             } elsif ( $order == 5 ) {
206 0           $dispersion = 4.6e-5;
207             } elsif ( $order == 4 ) {
208 0           $dispersion = 5.9e-5;
209             } elsif ( $order == 3 ) {
210 0           $dispersion = 7.8e-5;
211             } elsif ( $order == 2 ) {
212 0           $dispersion = 1.21e-4;
213             } elsif ( $order == 1 ) {
214 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.FILT1.ID"} ) {
215 0           my $filter = $FITS_headers->{"HIERARCH.ESO.INS.FILT1.ID"};
216 0 0         if ( $filter =~/SL/ ) {
217 0           $dispersion = 2.52e-4;
218             } else {
219 0           $dispersion = 2.39e-4;
220             }
221             } else {
222 0           $dispersion = 2.46e-4;
223             }
224             }
225             }
226             }
227             # }
228 0           return $dispersion;
229             }
230              
231             # If the telescope offset exists in arcsec, then use it. Otherwise
232             # convert the Cartesian offsets to equatorial offsets.
233             sub to_RA_TELESCOPE_OFFSET {
234 0     0 0   my $self = shift;
235 0           my $FITS_headers = shift;
236 0           my $raoffset = 0.0;
237 0 0 0       if ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETA"} ) {
    0          
238 0           $raoffset = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETA"};
239              
240             } elsif ( exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} &&
241             exists $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} ) {
242              
243 0           my $pixscale = 0.148;
244 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"} ) {
245 0           $pixscale = $FITS_headers->{"HIERARCH.ESO.INS.PIXSCALE"};
246             }
247              
248             # Sometimes the first imaging cumulative offsets are non-zero contrary
249             # to the documentation.
250 0           my $expno = 1;
251 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"} ) {
252 0           $expno = $FITS_headers->{"HIERARCH.ESO.TPL.EXPNO"};
253             }
254 0           my ( $x_as, $y_as );
255 0           my $mode = uc( $self->get_instrument_mode($FITS_headers) );
256 0 0 0       if ( $expno == 1 && ( $mode eq "IMAGE" || $mode eq "POLARIMETRY" ) ) {
      0        
257 0           $x_as = 0.0;
258 0           $y_as = 0.0;
259             } else {
260 0           $x_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETX"} * $pixscale;
261 0           $y_as = $FITS_headers->{"HIERARCH.ESO.SEQ.CUMOFFSETY"} * $pixscale;
262             }
263              
264             # Define degrees to radians conversion and obtain the rotation angle.
265 0           my $dtor = atan2( 1, 1 ) / 45.0;
266              
267 0           my $rotangle = $self->rotation($FITS_headers);
268 0           my $cosrot = cos( $rotangle * $dtor );
269 0           my $sinrot = sin( $rotangle * $dtor );
270              
271             # Apply the rotation matrix to obtain the equatorial pixel offset.
272 0           $raoffset = -$x_as * $cosrot + $y_as * $sinrot;
273             }
274              
275             # The sense is reversed compared with UKIRT, as these measure the
276             # place on the sky, not the motion of the telescope.
277 0           return -1.0 * $raoffset;
278             }
279              
280             # Derive the translation between observing template and recipe name.
281             sub to_DR_RECIPE {
282 0     0 0   my $self = shift;
283 0           my $FITS_headers = shift;
284 0           my $recipe = "QUICK_LOOK";
285              
286             # Obtain the observing template. These are equivalent
287             # to the UKIRT OT science programmes and their tied DR recipes.
288             # However, there are some wrinkles and variations to be tested.
289 0           my $template = $FITS_headers->{"HIERARCH.ESO.TPL.ID"};
290 0           my $seq = $FITS_headers->{"HIERARCH.ESO.TPL.PRESEQ"};
291              
292 0 0 0       if ( $template =~ /ISAAC[SL]W_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        
293             $template =~ /ISAAC[SL]W_img_obs_GenericOffset/ ) {
294 0           $recipe = "JITTER_SELF_FLAT";
295              
296             } elsif ( $template eq "ISAACSW_img_cal_StandardStar" ||
297             $template eq "ISAACLW_img_cal_StandardStarOff" ||
298             $template eq "ISAACSW_img_tec_Zp" ||
299             $template eq "ISAACLW_img_tec_ZpNoChop" ||
300             $seq eq "ISAAC_img_cal_StandardStar" ||
301             $seq eq "ISAACLW_img_cal_StandardStarOff" ) {
302 0           $recipe = "JITTER_SELF_FLAT_APHOT";
303              
304             } elsif ( $template =~ /ISAAC[SL]W_img_obs_AutoJitterOffset/ ) {
305 0           $recipe = "CHOP_SKY_JITTER";
306              
307             # The following two perhaps should be using NOD_CHOP and a variant of
308             # NOD_CHOP_APHOT to cope with the three source images (central double
309             # flux) rather than four.
310             } elsif ( $template eq "ISAACLW_img_obs_AutoChopNod" ||
311             $seq eq "ISAACLW_img_obs_AutoChopNod" ) {
312 0           $recipe = "NOD_SELF_FLAT_NO_MASK";
313              
314             } elsif ( $template eq "ISAACLW_img_cal_StandardStar" ||
315             $template =~ /^ISAACLW_img_tec_Zp/ ||
316             $seq eq "ISAACLW_img_cal_StandardStar" ) {
317 0           $recipe = "NOD_SELF_FLAT_NO_MASK_APHOT";
318              
319             } elsif ( $template =~ /ISAAC[SL]W_img_cal_Darks/ ||
320             $seq eq "ISAAC_img_cal_Darks" ) {
321 0           $recipe = "REDUCE_DARK";
322              
323             } elsif ( $template =~ /ISAAC[SL]W_img_cal_TwFlats/ ) {
324 0           $recipe = "SKY_FLAT_MASKED";
325              
326             # Imaging spectroscopy. There appears to be no distinction
327             # for flats from target, hence no division into POL_JITTER and
328             # SKY_FLAT_POL.
329             } elsif ( $template eq "ISAACSW_img_obs_Polarimetry" ||
330             $template eq "ISAACSW_img_cal_Polarimetry" ) {
331 0           $recipe = "POL_JITTER";
332              
333             # Spectroscopy. EXTENDED_SOURCE may be more appropriate for
334             # the ISAACSW_spec_obs_GenericOffset template.
335             } elsif ( $template =~ /ISAAC[SL]W_spec_obs_AutoNodOnSlit/ ||
336             $template =~ /ISAAC[SL]W_spec_obs_GenericOffset/ ||
337             $template eq "ISAACLW_spec_obs_AutoChopNod" ) {
338 0           $recipe = "POINT_SOURCE";
339              
340             } elsif ( $template =~ /ISAAC[SL]W_spec_cal_StandardStar/ ||
341             $template eq "ISAACLW_spec_cal_StandardStarNod" ||
342             $template =~ /ISAAC[SL]W_spec_cal_AutoNodOnSlit/ ) {
343 0           $recipe = "STANDARD_STAR";
344              
345             } elsif ( $template =~ /ISAAC[SL]W_spec_cal_NightCalib/ ) {
346 0 0         if ( $self->_to_OBSERVATION_TYPE() eq "LAMP" ) {
    0          
347 0           $recipe = "LAMP_FLAT";
348             } elsif ( $self->_to_OBSERVATION_TYPE() eq "ARC" ) {
349 0           $recipe = "REDUCE_ARC";
350             } else {
351 0           $recipe = "REDUCE_SINGLE_FRAME";
352             }
353              
354             } elsif ( $template =~ /ISAAC[SL]W_spec_cal_Arcs/ ||
355             $seq eq "ISAAC_spec_cal_Arcs" ) {
356 0           $recipe = "REDUCE_ARC";
357              
358             } elsif ( $template =~ /ISAAC[SL]W_spec_cal_Flats/ ) {
359 0           $recipe = "LAMP_FLAT";
360             }
361 0           return $recipe;
362             }
363              
364             # Fixed values for the gain depend on the camera (SW or LW), and for LW
365             # the readout mode.
366             sub to_SPEED_GAIN {
367 0     0 0   my $self = shift;
368 0           my $FITS_headers = shift;
369 0           my $spd_gain = "Normal";
370 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.INS.MODE"} ) {
371 0 0         if ( $FITS_headers->{"HIERARCH.ESO.INS.MODE"} =~ /SW/ ) {
372 0           $spd_gain = "Normal";
373             } else {
374 0 0         if ( exists $FITS_headers->{"HIERARCH.ESO.DET.MODE.NAME"} ) {
375 0 0         if ( $FITS_headers->{"HIERARCH.ESO.DET.MODE.NAME"} =~ /LowBias/ ) {
376 0           $spd_gain = "HiGain";
377             } else {
378 0           $spd_gain = "Normal";
379             }
380             }
381             }
382             }
383 0           return $spd_gain;
384             }
385              
386             # Translate to the SLALIB name for reference frame in spectroscopy.
387             sub to_TELESCOPE {
388 0     0 0   my $self = shift;
389 0           my $FITS_headers = shift;
390 0           my $telescope = "VLT1";
391 0 0         if ( exists $FITS_headers->{TELESCOP} ) {
392 0           my $scope = $FITS_headers->{TELESCOP};
393 0 0         if ( defined( $scope ) ) {
394 0           $telescope = $scope;
395 0           $telescope =~ s/ESO-//;
396 0           $telescope =~ s/-U//g;
397             }
398             }
399 0           return $telescope;
400             }
401              
402             =back
403              
404             =head1 SEE ALSO
405              
406             C<Astro::FITS::HdrTrans>, C<Astro::FITS::HdrTrans::UKIRT>.
407              
408             =head1 AUTHOR
409              
410             Malcolm J. Currie E<lt>mjc@star.rl.ac.ukE<gt>
411             Brad Cavanagh E<lt>b.cavanagh@jach.hawaii.eduE<gt>,
412             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>.
413              
414             =head1 COPYRIGHT
415              
416             Copyright (C) 2008 Science and Technology Facilities Council.
417             Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
418             All Rights Reserved.
419              
420             This program is free software; you can redistribute it and/or modify it under
421             the terms of the GNU General Public License as published by the Free Software
422             Foundation; either Version 2 of the License, or (at your option) any later
423             version.
424              
425             This program is distributed in the hope that it will be useful,but WITHOUT ANY
426             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
427             PARTICULAR PURPOSE. See the GNU General Public License for more details.
428              
429             You should have received a copy of the GNU General Public License along with
430             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
431             Place, Suite 330, Boston, MA 02111-1307, USA.
432              
433             =cut
434              
435             1;