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