File Coverage

blib/lib/Astro/PAL.pm
Criterion Covered Total %
statement 101 129 78.2
branch 11 30 36.6
condition n/a
subroutine 26 29 89.6
pod 7 7 100.0
total 145 195 74.3


line stmt bran cond sub pod time code
1             package Astro::PAL;
2              
3             =head1 NAME
4              
5             Astro::PAL - Perl interface to Starlink PAL positional astronomy library
6              
7             =head1 SYNOPSIS
8              
9             use PAL;
10             use PAL qw(:constants :pal);
11              
12             ($ra2000, $dec2000) = palFk45z($ra, $dec, 1950.0);
13             ($mjd, $status) = palCldj($yy, $mn, $dd);
14              
15             ($lst, $mjd) = lstnow($long);
16             ($lst, $mjd) = ut2lst_tel($yy,$mn,$dd,$hh,$mm,$ss,'JCMT');
17              
18             =head1 DESCRIPTION
19              
20             This modules provides a Perl interface to either the Starlink
21             PAL positional astronomy library.
22              
23             Return values are returned on the stack rather than being modified
24             in place.
25              
26             In addition small utility subroutines are provided that
27             do useful tasks (from the author's point of view) - specifically
28             routines for calculating the Local Sidereal Time.
29              
30             =cut
31              
32             # ' -- close quote for my 'authors' apostrophe above.
33              
34 7     7   438583 use strict;
  7         63  
  7         185  
35 7     7   34 use Carp;
  7         12  
  7         349  
36 7     7   39 use vars qw($VERSION %EXPORT_TAGS);
  7         13  
  7         343  
37              
38 7     7   34 use Exporter 'import';
  7         10  
  7         233  
39 7     7   57 use base qw/ DynaLoader /;
  7         18  
  7         4372  
40              
41             $VERSION = '1.08';
42              
43             %EXPORT_TAGS = (
44             'pal'=>[qw/
45             palAddet
46             palAirmas
47             palAltaz
48             palAmp
49             palAmpqk
50             palAop
51             palAoppa
52             palAoppat
53             palAopqk
54             palAtmdsp
55             palCaldj
56             palCldj
57             palDaf2r
58             palDafin
59             palDat
60             palDav2m
61             palDbear
62             palDcc2s
63             palDcmpf
64             palDcs2c
65             palDd2tf
66             palDe2h
67             palDeuler
68             palDfltin
69             palDh2e
70             palDimxv
71             palDjcal
72             palDjcl
73             palDm2av
74             palDmoon
75             palDmxm
76             palDmxv
77             palDpav
78             palDr2af
79             palDr2tf
80             palDrange
81             palDranrm
82             palDs2tp
83             palDsep
84             palDsepv
85             palDt
86             palDtf2d
87             palDtf2r
88             palDtp2s
89             palDtps2c
90             palDtt
91             palDvdv
92             palDvn
93             palDvxv
94             palEcmat
95             palEcleq
96             palEpb
97             palEpb2d
98             palEpco
99             palEpj
100             palEpj2d
101             palEpv
102             palEqecl
103             palEqeqx
104             palEqgal
105             palEtrms
106             palEvp
107             palFk45z
108             palFk524
109             palFk54z
110             palFitxy
111             palGaleq
112             palGalsup
113             palGeoc
114             palGmst
115             palGmsta
116             palHfk5z
117             palIntin
118             palInvf
119             palMap
120             palMappa
121             palMapqk
122             palMapqkz
123             palNut
124             palNutc
125             palOap
126             palOapqk
127             palObs
128             palPa
129             palPcd
130             palPertel
131             palPertue
132             palPlanel
133             palPlanet
134             palPlante
135             palPm
136             palPolmo
137             palPrebn
138             palPrec
139             palPreces
140             palPrenut
141             palPvobs
142             palPxy
143             palRdplan
144             palRefco
145             palRefcoq
146             palRefro
147             palRefv
148             palRefz
149             palRverot
150             palRvgalc
151             palRvlg
152             palRvlsrd
153             palRvlsrk
154             palSubet
155             palSupgal
156             palUnpcd
157             palXy2xy
158             /],
159             'constants'=>[qw/
160             DPI D2PI D1B2PI D4PI D1B4PI DPISQ DSQRPI DPIBY2
161             DD2R DR2D DAS2R DR2AS DH2R DR2H DS2R DR2S D15B2P
162             /],
163             'funcs'=>[qw/
164             lstnow lstnow_tel ut2lst ut2lst_tel
165             /]
166             );
167              
168              
169             Exporter::export_tags('pal','constants','funcs');
170              
171             bootstrap Astro::PAL;
172              
173              
174             =head1 Routines
175              
176             There are 3 distinct groups of routines that can be imported into
177             the namespace via tags:
178              
179             =over 4
180              
181             =item pal - import just the PAL routines
182              
183             =item constants - import the PAL constants
184              
185             =item funcs - import the extra routines
186              
187             =back
188              
189             Each group will be discussed in turn.
190              
191             =head2 PAL
192              
193             The PAL routines directly match the C API with the caveat that returned
194             values are returned on the perl argument stack rather than being modified
195             directly in the call arguments. Arguments are never modified. This differs
196             from the Astro::SLA wrapper around the SLALIB library.
197              
198             For example,
199              
200             ($xi, $eta, $j) = palDst2p( $ra, $dec, $raz, $decz );
201             @pv = palDmoon( $date );
202             ($nstrt, $fd, $j) = palDafin( $time, $nstrt );
203              
204              
205             If a routine returns an array as well as a status the status value
206             is returned first:
207              
208             ($j, @iymsf) = palDjcal( $ndp, $djm );
209              
210             If a routine returns multiple arrays they are returned as references:
211              
212             ($dvb, $dpb, $dvh, $dph) = palEvp( $date, $deqx );
213             @dvbarr = @$dvb;
214              
215             Routines that take vectors or matrices should be given references
216             to arrays:
217              
218             @rmatn = palNut( $djtt );
219             @mposr = palDmxv( \@rmatn, \@mpos );
220              
221             See the PAL or SLALIB documentation for details of the functions
222             themselves.
223              
224             =head3 Anomalies
225              
226             =over 4
227              
228             =item palObs
229              
230             palObs is special in that it returns an empty list if the return
231             status is bad. Additionally, palObs is called with a single
232             argument and the behaviour depends on whether the argument looks
233             like an integer or a string.
234              
235             ($ident, $name, $w, $p, $h) = palObs( 27 );
236             ($ident, $name, $w, $p, $h) = palObs( "JCMT" );
237              
238             =cut
239              
240             # We need a local version of palObs that converts the single
241             # argument to the right form for the internal XS implementation
242              
243             sub palObs {
244 11     11 1 24359 my $arg = shift;
245 11 50       32 return () unless defined $arg;
246              
247 11         14 my $n = 0;
248 11         15 my $c = "";
249              
250 11 100       50 if ( $arg =~ /^\d+$/) {
251 4         8 $n = $arg;
252             } else {
253 7         15 $c = $arg;
254             }
255              
256 11         157 return _palObs( $n, $c );
257             }
258              
259             =item palAopqk
260              
261             palAopqk can be called either with a reference to an
262             array or a list
263              
264             @results = palAopqk( $rap, $dap, @aoprms );
265             @results = palAopqk( $rap, $dap, \@aoprms );
266              
267             =cut
268              
269             # Sanity check argument counting before passing to XS layer
270              
271             sub palAopqk {
272 0     0 1 0 my $rap = shift;
273 0         0 my $dap = shift;
274              
275 0         0 my @aoprms;
276 0 0       0 if (@_ > 1) {
277 0         0 @aoprms = @_;
278             } else {
279 0         0 @aoprms = @{$_[0]};
  0         0  
280             }
281 0 0       0 croak "palAopqk: Need 14 elements in star-independent apparent to observed array"
282             unless @aoprms == 14;
283              
284 0         0 return pal_Aopqk( $rap, $dap, \@aoprms );
285             }
286              
287             =item palAoppat
288              
289             For the C API the calling convention is to modify the AOPRMS array in
290             place, for the perl API we accept the AOPRMS array but return the
291             updated version.
292              
293             @aoprms = Astro::PAL::palAoppat( $date, \@aoprms );
294             @aoprms = Astro::PAL::palAoppat( $date, @aoprms );
295              
296             =cut
297              
298             sub palAoppat {
299 1 50   1 1 26579 croak 'Usage: palAoppat( date, @aoprms )'
300             unless @_ > 1;
301              
302 1         2 my $date = shift;
303              
304 1         2 my @aoprms;
305 1 50       3 if (@_ > 1) {
306 1         3 @aoprms = @_;
307             } else {
308 0         0 @aoprms = @{$_[0]};
  0         0  
309             }
310              
311 1 50       4 croak "palAoppat: Need 14 elements in star-independent apparent to observed array"
312             unless @aoprms == 14;
313              
314 1         30 $aoprms[13] = pal_Aoppat( $date, $aoprms[12] );
315              
316 1         21 return @aoprms;
317              
318             }
319              
320              
321             # palAoppat C interface requires the full @AOPRMS array and simply updates
322             # element 13 based on element 12.
323              
324             =back
325              
326             =head2 Constants
327              
328             Constants supplied by this module (note that they are implemented via the
329             L pragma):
330              
331             =over 4
332              
333             =item DPI - Pi
334              
335             =item D2PI - 2 * Pi
336              
337             =item D1B2PI - 1 / (2 * Pi)
338              
339             =item D4PI - 4 * Pi
340              
341             =item D1B4PI - 1 / (4 * Pi)
342              
343             =item DPISQ - Pi ** 2 (Pi squared)
344              
345             =item DSQRPI - sqrt(Pi)
346              
347             =item DPIBY2 - Pi / 2: 90 degrees in radians
348              
349             =item DD2R - Pi / 180: degrees to radians
350              
351             =item DR2D - 180/Pi: radians to degrees
352              
353             =item DAS2R - pi/(180*3600): arcseconds to radians
354              
355             =item DR2AS - 180*3600/pi: radians to arcseconds
356              
357             =item DH2R - pi/12: hours to radians
358              
359             =item DR2H - 12/pi: radians to hours
360              
361             =item DS2R - pi / (12*3600): seconds of time to radians
362              
363             =item DR2S - 12*3600/pi: radians to seconds of time
364              
365             =item D15B2P - 15/(2*pi): hours to degrees * radians to turns
366              
367             =back
368              
369             =cut
370              
371             # Could implement these directly via the include file in the XS layer.
372             # Since these cant change - implement them explicitly.
373              
374             # Pi
375 7     7   52 use constant DPI => 3.1415926535897932384626433832795028841971693993751;
  7         10  
  7         661  
376              
377             # 2pi
378 7     7   42 use constant D2PI => 6.2831853071795864769252867665590057683943387987502;
  7         10  
  7         314  
379              
380             # 1/(2pi)
381 7     7   33 use constant D1B2PI => 0.15915494309189533576888376337251436203445964574046;
  7         18  
  7         324  
382              
383             # 4pi
384 7     7   38 use constant D4PI => 12.566370614359172953850573533118011536788677597500;
  7         15  
  7         296  
385              
386             # 1/(4pi)
387 7     7   44 use constant D1B4PI => 0.079577471545947667884441881686257181017229822870228;
  7         10  
  7         294  
388              
389             # pi^2
390 7     7   42 use constant DPISQ => 9.8696044010893586188344909998761511353136994072408;
  7         11  
  7         327  
391              
392             # sqrt(pi)
393 7     7   35 use constant DSQRPI => 1.7724538509055160272981674833411451827975494561224;
  7         11  
  7         286  
394              
395             # pi/2: 90 degrees in radians
396 7     7   43 use constant DPIBY2 => 1.5707963267948966192313216916397514420985846996876;
  7         21  
  7         307  
397              
398             # pi/180: degrees to radians
399 7     7   37 use constant DD2R => 0.017453292519943295769236907684886127134428718885417;
  7         13  
  7         263  
400              
401             # 180/pi: radians to degrees
402 7     7   34 use constant DR2D => 57.295779513082320876798154814105170332405472466564;
  7         10  
  7         354  
403              
404             # pi/(180*3600): arcseconds to radians
405 7     7   37 use constant DAS2R => 4.8481368110953599358991410235794797595635330237270e-6;
  7         11  
  7         340  
406              
407             # 180*3600/pi : radians to arcseconds
408 7     7   36 use constant DR2AS => 2.0626480624709635515647335733077861319665970087963e5;
  7         9  
  7         275  
409              
410             # pi/12: hours to radians
411 7     7   32 use constant DH2R => 0.26179938779914943653855361527329190701643078328126;
  7         12  
  7         286  
412              
413             # 12/pi: radians to hours
414 7     7   34 use constant DR2H => 3.8197186342054880584532103209403446888270314977709;
  7         17  
  7         319  
415              
416             # pi/(12*3600): seconds of time to radians
417 7     7   39 use constant DS2R => 7.2722052166430399038487115353692196393452995355905e-5;
  7         9  
  7         277  
418              
419             # 12*3600/pi: radians to seconds of time
420 7     7   33 use constant DR2S => 1.3750987083139757010431557155385240879777313391975e4;
  7         12  
  7         279  
421              
422             # 15/(2pi): hours to degrees x radians to turns
423 7     7   37 use constant D15B2P => 2.3873241463784300365332564505877154305168946861068;
  7         11  
  7         3888  
424              
425              
426             =head2 Extra functions
427              
428             These are exportable using the 'funcs' tag or used directly
429             through the Astro::PAL namespace.
430              
431             They directly match the Astro::SLA equivalents.
432              
433             =over 4
434              
435             =item B
436              
437             Return current LST (in radians) and MJD for a given telescope.
438             The telescope identifiers should match those present in palObs.
439             The supplied telescope name is converted to upper case.
440              
441             ($lst, $mjd) = lstnow_tel($tel);
442              
443             Aborts if telescope name is unknown.
444              
445             =cut
446              
447             sub lstnow_tel {
448              
449 0 0   0 1 0 croak 'Usage: lstnow_tel($tel)' unless scalar(@_) == 1;
450              
451 0         0 my $tel = shift;
452              
453             # Upper case the telescope
454 0         0 $tel = uc($tel);
455              
456             # Find the longitude of this telescope
457 0         0 my ($ident, $name, $w, $p, $h) = palObs( $tel );
458              
459             # Check telescope name
460 0 0       0 croak "Telescope name $tel unrecognised by palObs()"
461             unless defined $ident;
462              
463             # Convert longitude to west negative
464 0         0 $w *= -1.0;
465              
466             # Run lstnow
467 0         0 lstnow($w);
468              
469             }
470              
471              
472             =item B
473              
474             Return current LST (in radians) and MJD (days)
475             Longitude should be negative if degrees west
476             and in radians.
477              
478             ($lst, $mjd) = lstnow($long);
479              
480             =cut
481              
482             sub lstnow {
483              
484 0 0   0 1 0 croak 'Usage: lstnow($long)' unless scalar(@_) == 1;
485              
486 0         0 my $long = shift;
487              
488 0         0 my ($sign, @ihmsf);
489              
490             # Get current UT time
491 0         0 my ($sec, $min, $hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
492              
493             # Calculate LST
494 0         0 $year += 1900;
495 0         0 $mon++;
496 0         0 my ($lst, $mjd) = ut2lst($year, $mon, $mday, $hour, $min, $sec, $long);
497              
498 0         0 return ($lst, $mjd);
499              
500             }
501              
502              
503             =item B
504              
505             Given the UT time, calculate the Modified Julian date (UTC) and the
506             local sidereal time (radians) for the specified longitude.
507              
508             ($lst, $mjd) = ut2lst(yy, mn, dd, hh, mm, ss, long)
509              
510             Longitude should be negative if degrees west and in radians.
511              
512             =cut
513              
514             sub ut2lst {
515              
516 2 50   2 1 8 croak 'Usage: ut2lst(yy,mn,dd,hh,mm,ss,long)'
517             unless scalar(@_) == 7;
518              
519 2         7 my ($yy, $mn, $dd, $hh, $mm, $ss, $long) = @_;
520              
521             # Calculate fraction of day
522 2         49 my ($fd, $j) = palDtf2d($hh, $mm, $ss);
523 2 50       9 if ($j != 0) {
524 0         0 croak "Error calculating fractional day with H=$hh M=$mm S=$ss\n";
525             }
526              
527             # Calculate modified julian date of UT day
528 2         20 my ($mjd, $palstatus) = palCldj($yy, $mn, $dd);
529              
530 2 50       8 if ($palstatus != 0) {
531 0         0 croak "Error calculating modified Julian date with args: $yy $mn $dd\n";
532             }
533              
534             # Calculate sidereal time of greenwich
535 2         27 my $gmst = palGmsta($mjd, $fd);
536              
537             # Find MJD of current time (not just day)
538 2         5 $mjd += $fd;
539              
540             # Equation of the equinoxes (requires TT although makes very
541             # little differnece)
542 2         25 my $tt = $mjd + ( palDtt($mjd) / 86_400.0);
543 2         494 my $eqeqx = palEqeqx($tt);
544              
545             # Local sidereal time = GMST + EQEQX + Longitude in radians
546 2         13 my $lst = palDranrm($gmst + $eqeqx + $long);
547              
548 2         10 return ($lst, $mjd);
549             }
550              
551             =item B
552              
553             Given the UT time, calculate the Modified Julian date and the
554             local sidereal time (radians) for the specified telescope.
555              
556             ($lst, $mjd) = ut2lst_tel(yy, mn, dd, hh, mm, ss, tel)
557              
558             =cut
559              
560             sub ut2lst_tel ($$$$$$$) {
561 2 50   2 1 1451 croak 'Usage: ut2lst_tel($tel)' unless scalar(@_) == 7;
562              
563 2         8 my $tel = pop(@_);
564              
565             # Upper case the telescope
566 2         5 $tel = uc($tel);
567              
568             # Find the longitude of this telescope
569 2         8 my ($ident, $name, $w, $p, $h) = palObs($tel);
570              
571             # Check telescope name
572 2 50       10 croak "Telescope name $tel unrecognised by palObs()"
573             unless defined $ident;
574              
575             # Convert longitude to west negative
576 2         5 $w *= -1.0;
577              
578             # Run ut2lst
579 2         7 return ut2lst(@_, $w);
580              
581             }
582              
583             =back
584              
585              
586             =head1 AUTHOR
587              
588             Tim Jenness Etjenness@cpan.orgE
589              
590             =head1 REQUIREMENTS
591              
592             The PAL library is available from Starlink.
593              
594             =head1 COPYRIGHT
595              
596             Copyright (C) 2014 Tim Jenness
597             Copyright (C) 2012 Tim Jenness and the Science and Technology Facilities
598             Council.
599              
600             This program is free software; you can redistribute it and/or modify it under
601             the terms of the GNU General Public License as published by the Free Software
602             Foundation; either version 3 of the License, or (at your option) any later
603             version.
604              
605             This program is distributed in the hope that it will be useful,but WITHOUT ANY
606             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
607             PARTICULAR PURPOSE. See the GNU General Public License for more details.
608              
609             You should have received a copy of the GNU General Public License along with
610             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
611             Place,Suite 330, Boston, MA 02111-1307, USA
612              
613             =cut
614              
615             1;