File Coverage

blib/lib/Astro/FITS/HdrTrans/ISAAC.pm
Criterion Covered Total %
statement 15 156 9.6
branch 0 112 0.0
condition 0 69 0.0
subroutine 6 14 42.8
pod 2 9 22.2
total 23 360 6.3


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