| Astro-FITS-HdrTrans documentation | Contained in the Astro-FITS-HdrTrans distribution. |
Astro::FITS::HdrTrans::JCMT_GSD_DB - JCMT GSD Database header translations
Converts information contained in JCMT heterodyne database headers to and from generic headers. See Astro::FITS::HdrTrans for a list of generic headers.
Returns true if the supplied headers can be handled by this class.
$cando = $class->can_translate( \%hdrs );
For this class, the method will return true if the "GSDFILE" header exists and the "SCA#" header exist.
These methods are more complicated than a simple mapping. We have to provide both from- and to-FITS conversions All these routines are methods and the to_ routines all take a reference to a hash and return the translated value (a many-to-one mapping) The from_ methods take a reference to a generic hash and return a translated hash (sometimes these are many-to-many)
Sets the INSTRUMENT generic header. For RxA3i, sets the value
to RXA3. For RxB, sets the value to RXB3.
Calculate a unique Observation ID.
Translates the DATE_OBS or LONGDATEOBS header into a
YYYYMMDD integer.
Translates the DB date header into a Time::Piece object.
Translates the database date header into a Time::Piece object and adds
on the exposure time.
Uses the NORSECT (number of backend sections), NOFCHAN (number of frontend output channels) and NOBCHAN (number of channels) to form a string that is of the format 250MHzx2048. To obtain this, the bandwidth (250MHz in this example) is calculated as 125MHz * NORSECT / NOFCHAN. The number of channels is taken directly and not manipulated in any way.
If appropriate, the bandwidth may be given in GHz.
Translate the VREF and C12VDEF headers into one combined header.
$Id$
Brad Cavanagh <b.cavanagh@jach.hawaii.edu>, Tim Jenness <t.jenness@jach.hawaii.edu>
Copyright (C) 2008 Science and Technology Facilities Council. Copyright (C) 2003-2007 Particle Physics and Astronomy Research Council. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place,Suite 330, Boston, MA 02111-1307, USA
| Astro-FITS-HdrTrans documentation | Contained in the Astro-FITS-HdrTrans distribution. |
package Astro::FITS::HdrTrans::JCMT_GSD_DB;
use 5.006; use warnings; use strict; use Carp; use Time::Piece; # Inherit from Base use base qw/ Astro::FITS::HdrTrans::Base /; use vars qw/ $VERSION /; $VERSION = "1.50"; # for a constant mapping, there is no FITS header, just a generic # header that is constant my %CONST_MAP = ( INST_DHS => 'HET_GSD', COORDINATE_UNITS => 'decimal', EQUINOX => 'current', TELESCOPE => 'JCMT', ); # NULL mappings used to override base class implementations my @NULL_MAP = (); # unit mapping implies that the value propogates directly # to the output with only a keyword name change my %UNIT_MAP = ( AMBIENT_TEMPERATURE => "TAMB", APERTURE => "APERTURE", AZIMUTH_START => "AZ", BACKEND => "BACKEND", BACKEND_SECTIONS => "NORSECT", CHOP_FREQUENCY => "CHOPFREQ", CHOP_THROW => "CHOPTHRW", COORDINATE_SYSTEM => "COORDCD", # COORDINATE_TYPE => "C4LSC", CYCLE_LENGTH => "CYCLLEN", # DEC_BASE => "", ELEVATION_START => "EL", FILENAME => "GSDFILE", FILTER => "FILTER", FREQUENCY_RESOLUTION => "FREQRES", FRONTEND => "FRONTEND", HUMIDITY => "HUMIDITY", NUMBER_OF_CYCLES => "NOCYCLES", NUMBER_OF_SUBSCANS => "NOSCANS", OBJECT => "OBJECT", OBSERVATION_MODE => "OBSMODE", OBSERVATION_NUMBER => "SCAN", PROJECT => "PROJID", # RA_BASE => "C4RADATE", RECEIVER_TEMPERATURE => "TRX", ROTATION => "YPOSANG", REST_FREQUENCY => "RESTFRQ1", SEEING => "PHA", SWITCH_MODE => "SWMODE", SYSTEM_TEMPERATURE => "STSYS", TAU => "TAU", USER_AZ_CORRECTION => "UXPNT", USER_EL_CORRECTION => "UYPNT", VELOCITY => "VELOCITY", VELOCITY_REFERENCE_FRAME => "VREF", VELOCITY_TYPE => "VDEF", X_BASE => "XREF", Y_BASE => "YREF", X_DIM => "NOXPTS", Y_DIM => "NOYPTS", X_REQUESTED => "XSOURCE", Y_REQUESTED => "YSOURCE", X_SCALE => "DELTAX", Y_SCALE => "DELTAY", ); # Create the translation methods __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP, \@NULL_MAP );
sub can_translate { my $self = shift; my $headers = shift; if (exists $headers->{GSDFILE} && exists $headers->{"SCA#"}) { return 1; } return 0; }
sub to_INSTRUMENT { my $self = shift; my $FITS_headers = shift; my $return; if ( exists( $FITS_headers->{'FRONTEND'} ) ) { $return = $FITS_headers->{'FRONTEND'}; if ( $return =~ /^rxa3/i ) { $return = "RXA3"; } elsif ( $return =~ /^rxb/i ) { $return = "RXB3"; } } return $return; }
# Note this routine is generic for JCMT heterodyne instrumentation. # Would be completely generic if BACKEND was not used in preference to instrument. sub to_OBSERVATION_ID { my $self = shift; my $FITS_headers = shift; my $backend = lc( $self->to_BACKEND( $FITS_headers ) ); my $obsnum = $self->to_OBSERVATION_NUMBER( $FITS_headers ); my $dateobs = $self->to_UTSTART( $FITS_headers ); my $datetime = $dateobs->datetime; $datetime =~ s/-//g; $datetime =~ s/://g; my $obsid = join('_', $backend, $obsnum, $datetime); return $obsid; }
sub to_UTDATE { my $self = shift; my $FITS_headers = shift; my $date = _sybase_convert_date( _date_header( $FITS_headers ), 1); return $date->strftime('%Y%m%d'); }
sub to_UTSTART { my $self = shift; my $FITS_headers = shift; return _sybase_convert_date( _date_header( $FITS_headers )); }
sub to_UTEND { my $self = shift; my $FITS_headers = shift; my $return = _sybase_convert_date( _date_header( $FITS_headers ) ); return undef unless defined $return; my $expt = $self->to_EXPOSURE_TIME( $FITS_headers ); $return += $expt; return $return; }
sub to_BANDWIDTH_MODE { my $self = shift; my $FITS_headers = shift; my $return; if ( exists( $FITS_headers->{'NORSECT'} ) && defined( $FITS_headers->{'NORSECT'} ) && exists( $FITS_headers->{'NOFCHAN'} ) && defined( $FITS_headers->{'NOFCHAN'} ) && exists( $FITS_headers->{'NOBCHAN'} ) && defined( $FITS_headers->{'NOBCHAN'} ) ) { my $bandwidth = 125 * $FITS_headers->{'NORSECT'} / $FITS_headers->{'NOFCHAN'}; if ( $bandwidth >= 1000 ) { $bandwidth /= 1000; $return = sprintf( "%dGHzx%d", $bandwidth, $FITS_headers->{'NOBCHAN'} ); } else { $return = sprintf( "%dMHzx%d", $bandwidth, $FITS_headers->{'NOBCHAN'} ); } } return $return; }
sub to_EXPOSURE_TIME { my $self = shift; my $FITS_headers = shift; my $expt = 0; if ( exists( $FITS_headers->{'OBSMODE'} ) && defined( $FITS_headers->{'OBSMODE'} ) ) { my $obsmode = uc( $FITS_headers->{'OBSMODE'} ); if ( $obsmode eq 'RASTER' ) { if ( exists( $FITS_headers->{'NSCAN'} ) && defined( $FITS_headers->{'NSCAN'} ) && exists( $FITS_headers->{'CYCLLEN'} ) && defined( $FITS_headers->{'CYCLLEN'} ) && exists( $FITS_headers->{'NOCYCPTS'} ) && defined( $FITS_headers->{'NOCYCPTS'} ) ) { my $nscan = $FITS_headers->{'NSCAN'}; my $cycllen = $FITS_headers->{'CYCLLEN'}; my $nocycpts = $FITS_headers->{'NOCYCPTS'}; # raster. $expt = 15 + $nscan * $cycllen * ( 1 + 1 / sqrt( $nocycpts ) ) * 1.4; } } elsif ( $obsmode eq 'PATTERN' or $obsmode eq 'GRID' ) { my $swmode = ''; if ( exists( $FITS_headers->{'SWMODE'} ) && defined( $FITS_headers->{'SWMODE'} ) ) { $swmode = $FITS_headers->{'SWMODE'}; } else { $swmode = 'BEAMSWITCH'; } if ( exists( $FITS_headers->{'NSCAN'} ) && defined( $FITS_headers->{'NSCAN'} ) && exists( $FITS_headers->{'NCYCLE'} ) && defined( $FITS_headers->{'NCYCLE'} ) && exists( $FITS_headers->{'CYCLLEN'} ) && defined( $FITS_headers->{'CYCLLEN'} ) ) { my $nscan = $FITS_headers->{'NSCAN'}; my $ncycle = $FITS_headers->{'NCYCLE'}; my $cycllen = $FITS_headers->{'CYCLLEN'}; if ( $swmode eq 'POSITION_SWITCH' ) { # position switch pattern/grid. $expt = 6 + $nscan * $ncycle * $cycllen * 1.35; } elsif ( $swmode eq 'BEAMSWITCH' ) { # beam switch pattern/grid. $expt = 6 + $nscan * $ncycle * $cycllen * 1.35; } elsif ( $swmode eq 'CHOPPING' ) { if ( exists( $FITS_headers->{'FRONTEND'} ) && defined( $FITS_headers->{'FRONTEND'} ) ) { my $frontend = uc( $FITS_headers->{'FRONTEND'} ); if ( $frontend eq 'RXA3I' ) { # fast frequency switch pattern/grid, receiver A. $expt = 15 + $nscan * $ncycle * $cycllen * 1.20; } elsif ( $frontend eq 'RXB' ) { # slow frequency switch pattern/grid, receiver B. $expt = 18 + $nscan * $ncycle * $cycllen * 1.60; } } } } } else { my $swmode; if ( exists( $FITS_headers->{'SWMODE'} ) && defined( $FITS_headers->{'SWMODE'} ) ) { $swmode = uc( $FITS_headers->{'SWMODE'} ); } else { $swmode = 'BEAMSWITCH'; } if ( exists( $FITS_headers->{'NSCAN'} ) && defined( $FITS_headers->{'NSCAN'} ) && exists( $FITS_headers->{'NCYCLE'} ) && defined( $FITS_headers->{'NCYCLE'} ) && exists( $FITS_headers->{'CYCLLEN'} ) && defined( $FITS_headers->{'CYCLLEN'} ) ) { my $nscan = $FITS_headers->{'NSCAN'}; my $ncycle = $FITS_headers->{'NCYCLE'}; my $cycllen = $FITS_headers->{'CYCLLEN'}; if ( $swmode eq 'POSITION_SWITCH' ) { # position switch sample. $expt = 4.8 + $nscan * $ncycle * $cycllen * 1.10; } elsif ( $swmode eq 'BEAMSWITCH' ) { # beam switch sample. $expt = 4.8 + $nscan * $ncycle * $cycllen * 1.25; } elsif ( $swmode eq 'CHOPPING' ) { if ( exists( $FITS_headers->{'FRONTEND'} ) && defined( $FITS_headers->{'FRONTEND'} ) ) { my $frontend = uc( $FITS_headers->{'FRONTEND'} ); if ( $frontend eq 'RXA3I' ) { # fast frequency switch sample, receiver A. $expt = 3 + $nscan * $ncycle * $cycllen * 1.10; } elsif ( $frontend eq 'RXB' ) { # slow frequency switch sample, receiver B. $expt = 3 + $nscan * $ncycle * $cycllen * 1.40; } } } } } } return $expt; }
sub to_SYSTEM_VELOCITY { my $self = shift; my $FITS_headers = shift; my $return; if ( exists( $FITS_headers->{'VREF'} ) && defined( $FITS_headers->{'VREF'} ) && exists( $FITS_headers->{'VDEF'} ) && defined( $FITS_headers->{'VDEF'} ) ) { $return = uc( substr( $FITS_headers->{'VDEF'}, 0, 3 ) . substr( $FITS_headers->{'VREF'}, 0, 3 ) ); } return $return; }
sub _date_header { my $FITS_headers = shift; for my $key (qw/ LONGDATEOBS DATE_OBS LONGDATE/ ) { if (exists $FITS_headers->{$key} && defined $FITS_headers->{$key}) { return $FITS_headers->{$key}; } } return; }
sub _sybase_convert_date { my $longdate = shift; my $drophms = shift; return undef unless $longdate; # The UT header is in Sybase format, which is something like # "Mar 15 2002 7:04:35:234AM ". We first need to remove the number # of milliseconds, then the whitespace at the end, then use the # "%b%t%d%t%Y%t%I:%M:%S%p" format. # General cleanup $longdate =~ s/:\d\d\d//; $longdate =~ s/\s*$//; my $return; if ($drophms) { $longdate =~ s/\s*\d\d?:\d\d:\d\d[A|P]M$//; $return = Time::Piece->strptime( $longdate, "%b %e %Y" ); } else { $return = Time::Piece->strptime( $longdate, "%b %e %Y %l:%M:%S%p" ); } return $return; }
1;