Aldebaran has asked for the wisdom of the Perl Monks concerning the following question:

Hello and happy perlukkah (why not),

It's nice to be able to roll in here with perl syntax that can calculate the coming conjunction of jupiter and saturn. Having a grown-up logging capability made the data so clear, so quick. I'll begin with output followed by source.

2020/12/11 00:28:28 INFO ./4.wm_fermi.pl 2020/12/11 00:28:33 INFO right ascension of jupiter 20h 11m 7s 2020/12/11 00:28:33 INFO right ascension of saturn 20h 11m 3s 2020/12/11 00:28:33 INFO jup seconds is 72667 2020/12/11 00:28:33 INFO sat seconds is 72663 2020/12/11 00:28:38 INFO right ascension of jupiter 20h 10m 16s 2020/12/11 00:28:38 INFO right ascension of saturn 20h 10m 38s 2020/12/11 00:28:38 INFO jup seconds is 72616 2020/12/11 00:28:38 INFO sat seconds is 72638 2020/12/11 00:28:42 INFO right ascension of jupiter 20h 10m 38s 2020/12/11 00:28:42 INFO right ascension of saturn 20h 10m 49s 2020/12/11 00:28:42 INFO jup seconds is 72638 2020/12/11 00:28:42 INFO sat seconds is 72649 2020/12/11 00:28:47 INFO right ascension of jupiter 20h 10m 53s 2020/12/11 00:28:47 INFO right ascension of saturn 20h 10m 56s 2020/12/11 00:28:47 INFO jup seconds is 72653 2020/12/11 00:28:47 INFO sat seconds is 72656 2020/12/11 00:28:51 INFO right ascension of jupiter 20h 11m 0s 2020/12/11 00:28:51 INFO right ascension of saturn 20h 11m 0s 2020/12/11 00:28:51 INFO jup seconds is 72660 2020/12/11 00:28:51 INFO sat seconds is 72660 2020/12/11 00:28:51 INFO equal, while condition fails at julian day 24 +59205.07717792 2020/12/11 00:28:51 INFO equal seconds is 72660

Source:

#!/usr/bin/env perl use warnings; use strict; use 5.010; use WWW::Mechanize; use HTML::TableExtract qw(tree); use open ':std', OUT => ':utf8'; use Prompt::Timeout; use constant TIMEOUT => 3; use constant MAXTRIES => 30; use Log::Log4perl; ## redesign for jupiter/saturn conjunction 2020 my $log_conf3 = "/home/hogan/Documents/hogan/logs/conf_files/3.conf"; my $log_conf4 = "/home/hogan/Documents/hogan/logs/conf_files/4.conf"; #Log::Log4perl::init($log_conf3); #debug Log::Log4perl::init($log_conf4); #info my $logger = Log::Log4perl->get_logger(); $logger->info($0); my $site = 'http://www.fourmilab.ch/yoursky/cities.html'; my $mech = WWW::Mechanize->new; $mech->get($site); $mech->follow_link( text => 'Portland OR' ); my $before_bound = 2459203.5; #before conjunction my $after_bound = 2459206.5; #after conjunction $mech->set_fields(qw'date 2'); my ( $moon_seconds, $sun_seconds ) = ( 5, 3 ); # unequal values to start script c +hugging my $upper = $after_bound; my $lower = $before_bound; my ( $equal, $equal_sec ); my $attempts = 1; while ( ( $sun_seconds != $moon_seconds ) ) { my $default = ( ( $attempts >= MAXTRIES ) ) ? 'N' : 'Y'; my $answer = prompt( "Make query number $attempts?", $default, TIME +OUT ); exit if $answer =~ /^N/i; my $guess = closetohalf( $upper, $lower ); $mech->set_fields( jd => $guess ); $mech->click_button( value => "Update" ); my $te = 'HTML::TableExtract'->new; $te->parse( $mech->content ); my $table = ( $te->tables )[3]; my $table_tree = $table->tree; my $moon = $table_tree->cell( 7, 1 )->as_text; $logger->info("right ascension of jupiter $moon"); my $sun = $table_tree->cell( 8, 1 )->as_text; $logger->info("right ascension of saturn $sun"); $moon_seconds = string_to_second($moon); $logger->info("jup seconds is $moon_seconds"); $sun_seconds = string_to_second($sun); $logger->info("sat seconds is $sun_seconds"); if ( $sun_seconds < $moon_seconds ) { $upper = $guess; } elsif ( $moon_seconds < $sun_seconds ) { $lower = $guess; } else { $equal = $guess; $logger->info("equal, while condition fails at julian day $equal") +; $equal_sec = $moon_seconds; } $te->delete; $attempts++; } $logger->info("equal seconds is $equal_sec"); sub string_to_second { my $string = shift; my $return = 9000; if ( my $success = $string =~ /^(\d*)h\s+(\d*)m\s+(\d*)s$/ ) { $return = 3600 * $1 + 60 * $2 + $3; } else { # log the error $logger->error("string was misformed $string"); die "string was misformed $!"; } return $return; } sub closetohalf { my ( $up, $low ) = @_; $low + ( $up - $low ) * ( 0.4 + rand 0.2 ); }

There's any number of things I'd like to accomplish with this thread; some are more perl-related than others. Comment on what you will but leave the rest for those of us who are captured by this moment. A little physics won't hurt us, will it?

Goal 1: I've had versions of this that calculate the endpoints precisely and then a mean. I'd like to reconstitute this capability.

Goal 2: Determine whether it's mathematically-possible that Jupiter occludes the earth from the point of view of Saturn or his rings, whatever they are.

Goal 3: Build a front end for this script with Mojolicious and perl standard toolkits. "Welcome to Conjunction Junction". It should have the planets, moon and sun in two different pull downs. Order should not matter. The choices should be constrained to be different. Then the script comes up with its output as the next conjunction of these objects. I'm presenting with 'Jupiter' and 'Saturn' hard-coded. A button should begin the calculation. Extra points if we can populate the solar system by the table we already have your sky.

Goal 4: Update variable names so that they don't become physically-wrong for the next version of this script.

Goal 5: Deploy onto server and be able to use from a browser.

I've tried to do this before and failed. The sticky wicket had been a shared host where I couldn't install perl modules at all. I have successes, however humble, with mojo

fred@fourth:~/mojo$ ls 1.button.pl 2.1.mojo_hello.pl 5.3.elev.debug.pl 1.myapp.pl 5.2.elev.pl 5.3.elev.pl fred@fourth:~/mojo$

I do have a working button, if invoked with a daemon. Thanks for comments,

Replies are listed 'Best First'.
Re: calculating planet conjunction with mojo front end
by marto (Cardinal) on Dec 11, 2020 at 09:52 UTC

    'Goal 3' if you look at previous threads of yours I've provided Mojo based implementations of similar sounding things already, or at least enough to leverage as a starting point for delivering this. The code you post here is not Mojo based. What did you try and how did it fail?

      'Goal 3' if you look at previous threads of yours I've provided Mojo based implementations of similar sounding things already, or at least enough to leverage as a starting point for delivering this. The code you post here is not Mojo based. What did you try and how did it fail?

      I looked through what you posted on my questions, and we were looking at this in April and May of this year, and I was very keen to know where the sun was going to be then. Many of the scripts I wrote then were mishmashes: I was experimenting, and it would all ultimately not get off the ground on my shared server.

      Then we had the perl conference, my first, and I realized everything had to change because everything had changed.

      $ pwd /home/hogan/mojo $ ls 1.button.pl 5.3.elev.debug.pl 5.3.elev.pl $

      Q1) How do grown-ups configure their mojo capability on their development machine? Is it, like me right, a single directory that will eventually have dozens of files with names that look almost the same. The way I can guess which one works is what has the highest number. But this can also be where I gave up the ghost on a string of bad ideas expressed in script.

      Q2) Since I have perlbrew on the remote server (recommended by mojo), should I install it on the laptop, i.e. the development machine?

      Let's tack to what parts work. Output, then source.

      2020/12/11 10:45:52 INFO ./3.mojo_fermi.pl 2020/12/11 10:45:53 INFO i is 0 ============== 2020/12/11 10:45:53 INFO <?xml version="1.0" encoding="iso-8859-1"?> 2020/12/11 10:45:53 INFO i is 1 ============== 2020/12/11 10:45:53 INFO 2020/12/11 10:45:53 INFO i is 2 ============== 2020/12/11 10:45:53 INFO <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 +Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2020/12/11 10:45:53 INFO i is 3 ============== 2020/12/11 10:45:53 INFO 2020/12/11 10:45:53 INFO i is 4 ============== 2020/12/11 10:45:53 INFO <html lang="en" xml:lang="en" xmlns="http://w +ww.w3.org/1999/xhtml"> <head> <title> Sky above 45°31&#39;5&quot;N 122°40&#39;33&quot;W at Fri 2020 Dec 11 1 +8:45 </title> </head> <body> snip <p /> <a href="/yoursky/help/ephemeris.html"><b>Ephemeris:</b></a><center> <table border="border" cellpadding="3"> <tr><th rowspan="2"> </th><th rowspan="2">Right<br />Ascension</th><th + rowspan="2">Declination</th><th rowspan="2">Distance<br />(<span tit +le="Astronomical units (149,597,871 km)">AU</span>)</th><th colspan=" +2">From 45°31&#39;5&quot;N 122°40&#39;33&quot;W:</th></tr> <tr><th>Altitude</th><th>Azimuth</th></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=0&amp;z=1">Sun</a></th><td + align="right">17h 17m 17s</td><td align="right">&#8722;23° 4.4&#39;< +/td><td align="right">0.985</td><td align="right">19.130</td><td alig +n="right">&#8722;19.052</td><td>Up</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=1&amp;z=1">Mercury</a></th +><td align="right">16h 56m 57s</td><td align="right">&#8722;23° 19.1& +#39;</td><td align="right">1.438</td><td align="right">19.910</td><td + align="right">&#8722;14.157</td><td>Up</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=2&amp;z=1">Venus</a></th>< +td align="right">15h 32m 32s</td><td align="right">&#8722;17° 41.8&#3 +9;</td><td align="right">1.480</td><td align="right">26.501</td><td a +lign="right">7.028</td><td>Up</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=3&amp;z=1">Moon</a></th><t +d align="right">14h 35m 51s</td><td align="right">&#8722;11° 41.4&#39 +;</td><td align="right">57.0 <span title="Earth radii (6378.14 km)">E +R</span></td><td align="right">29.801</td><td align="right">23.591</t +d><td>Up</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=4&amp;z=1">Mars</a></th><t +d align="right">1h 12m 37s</td><td align="right">+8° 4.4&#39;</td><td + align="right">0.725</td><td align="right">&#8722;24.754</td><td alig +n="right">&#8722;133.649</td><td>Set</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=5&amp;z=1">Jupiter</a></th +><td align="right">20h 2m 11s</td><td align="right">&#8722;20° 57.3&# +39;</td><td align="right">5.841</td><td align="right">3.667</td><td a +lign="right">&#8722;54.781</td><td>Up</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=6&amp;z=1">Saturn</a></th> +<td align="right">20h 6m 43s</td><td align="right">&#8722;20° 37.7&#3 +9;</td><td align="right">10.733</td><td align="right">3.271</td><td a +lign="right">&#8722;55.819</td><td>Up</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=7&amp;z=1">Uranus</a></th> +<td align="right">2h 20m 0s</td><td align="right">+13° 28.6&#39;</td> +<td align="right">19.043</td><td align="right">&#8722;26.910</td><td +align="right">&#8722;152.851</td><td>Set</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=8&amp;z=1">Neptune</a></th +><td align="right">23h 18m 20s</td><td align="right">&#8722;5° 39.9&# +39;</td><td align="right">29.945</td><td align="right">&#8722;17.891< +/td><td align="right">&#8722;100.409</td><td>Set</td></tr> <tr><th><a href="/cgi-bin/uncgi/Yourtel?aim=9&amp;z=1">Pluto</a></th>< +td align="right">19h 41m 19s</td><td align="right">&#8722;22° 34.9&#3 +9;</td><td align="right">34.999</td><td align="right">5.255</td><td a +lign="right">&#8722;49.911</td><td>Up</td></tr> </table> </center> <blockquote> snip </body> </html> 2020/12/11 10:45:53 INFO i is 5 ============== 2020/12/11 10:45:53 INFO

      Source:

      #!/usr/bin/perl use strict; use warnings; use Mojo::URL; use Mojo::Util qw(dumper); use Mojo::UserAgent; use Data::Dump; use Log::Log4perl; use 5.016; use Mojo::DOM; my $log_conf3 = "/home/hogan/Documents/hogan/logs/conf_files/3.conf"; my $log_conf4 = "/home/hogan/Documents/hogan/logs/conf_files/4.conf"; #Log::Log4perl::init($log_conf3); #debug Log::Log4perl::init($log_conf4); #info my $logger = Log::Log4perl->get_logger(); $logger->info("$0"); my $site = 'https://www.fourmilab.ch/cgi-bin/Yoursky?z=1&lat=45.5183&ns=North&lon +=122.676&ew=West'; # pretend to be a browser my $uaname = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like G +ecko) Chrome/40.0.2214.93 Safari/537.36'; my $ua = Mojo::UserAgent->new; $ua->max_redirects(5)->connect_timeout(20)->request_timeout(20); $ua->transactor->name($uaname); # find search results my $dom = $ua->get($site)->res->dom; # dd $dom; #overwhelms STDOUT say "==========="; my @nodes = @$dom; # c-style for is good for array output with index for ( my $i = 0 ; $i < @nodes ; $i++ ) { $logger->info("i is $i =============="); $logger->info("$nodes[$i]"); } sleep 2; #good hygiene __END__

      The ephemeris is when i=4 here. That's where we are gonna be fishing for values.

      The mojo syntax for tables is...idiomatic, but you gave me an example in Re: polishing up a json fetching script for weather data. Excerpting your response:

      say 'Julian Day: ' . $dt->jd; my $pturl = 'http://www.fourmilab.ch/cgi-bin/Yoursky?z=1&lat=45.5183& +ns=North&lon=122.676&ew=West'; # you wanted Julian date so it looks like date should be '2' from the +source. my $tx = $ua->post( $pturl => form => { utc => $dt->jd, date => '2' } +); my $sunrow = $tx->res->dom->at('center:nth-of-type(3) table tr:nth-of- +type(3)'); # output say 'Name:' . $sunrow->children->[0]->all_text; say 'Altitude: ' . $sunrow->children->[4]->text; say 'Azimuth: ' . $sunrow->children->[5]->text; say 'Visible: ' . $sunrow->children->[6]->text;

      So now I need to adapt this for Saturn and Jupiter, but I don't want to hard code that part this time: they should be selected. I think I can get this done with 2 sets of radio buttons, if a pull-down menu is more than I want to bite off at this point. So that's where I am tonight.

      I haven't started coding anew, wanting to rather begin with a reasonable write-up. Thanks for your comments,

        Q1) In terms of Mojolicious see Tutorial which introduces Mojolicious::Lite, where Growing takes you from Mojolicious::Lite to a more structured Mojolicious app, which may be overkill depending on your needs. In terms of development, look into version control, something like Git, the docs have some videos giving overviews etc. By using something along these lines you negate the need to keep multiple copies of the same thing (or very similar), with different names in an attempt to keep track of which changes broke what.

        Q2) Best practice to try and stick to the same perl and Mojolicious versions.

        "The mojo syntax for tables is...idiomatic"

        "So now I need to adapt this for Saturn and Jupiter, but I don't want to hard code that part this time: they should be selected. I think I can get this done with 2 sets of radio buttons, if a pull-down menu is more than I want to bite off at this point. So that's where I am tonight."

        As mentioned previously these are CSS selectors, $sunrow shows how to get the table row for the Sun. You'd just have to alter this selector based upon values from a drop down (or whatever) to select the details for the rows you wanted. You could even dynamically populate the drop down (or whatever) based on the values from the column in question. That said, if you are looking to host something yourself, I don't see why you're scraping this other site. Wouldn't it make more sense to calculate this stuff yourself? A very helpful Anonymous Monk has given some examples using the Astro namespace modules, Re^2: calculating planet conjunction with mojo front end for example.

Re: calculating planet conjunction with mojo front end
by bliako (Abbot) on Dec 11, 2020 at 13:37 UTC

    For Goals 1+2, can you start with describing the physics of the problem? I can see you make a guess which lies in the centre of a range with a 10% random deviation. Then you enter that guess into a remote web-based service and you get back two values which you compare until they are equal. If they are not you make a new guess within a new range which becomes smaller and smaller. There must be some equations governing these phenomena and perhaps you can solve them to get the answer analytically rather than with iterating? I am a complete newbie when it comes to the stars.

    Goal 3: I would start with the HTML (re: pulldowns etc), you probably require a form in order to sumbit user input to your back-end script. The back-end script can do the calculations and present them back to the webpage. Perhaps you can also present results by constructing an image on-the-fly via Perl (e.g. GD). I can see a bit of a problem when back-end processing takes some time to complete while the webpage says "waiting ...": timeouts, connection failures, exceeding web-host's CPU quota etc. can waste the backend processing and users retrying and clogging the system. I am not sure what a good system for that is: perhaps users submit jobs and when a job is completed an email/pdf is sent to them? Another idea is to add a database caching user requests. You may be able to save some processing this way (on the expense of setting+working a db).

    bw, bliako

      There must be some equations governing these phenomena and perhaps you can solve them to get the answer analytically rather than with iterating?

      Astro::Coords - Class for handling astronomical coordinates

      #!/usr/bin/perl use strict; use warnings; use Time::Piece; use Astro::Coords; print qq/Planet\tRight Ascension\t\tDeclination\n/; for my $name (qw/Jupiter Saturn/) { my $planet = Astro::Coords->new(planet => $name); $planet->datetime(Time::Piece->new); my $ra = $planet->ra(format => q/deg/); my $dec = $planet->dec(format => q/deg/); print qq/$name\t$ra\t$dec\n/ }
      Output:
      Planet	Right Ascension		Declination
      Jupiter	300.231916167496	-21.0148733591416
      Saturn	301.371438440471	-20.6884105467964
      
      One-liner:
      perl -MAstro::Coords -MTime::Piece -Mstrict -e 'print qq/Planet\tRight + Ascension\t\tDeclination\n/; for my $name (qw/Jupiter Saturn/) { my +$planet = Astro::Coords->new(planet => $name); $planet->datetime(Time +::Piece->new); my $ra = $planet->ra(format => q/deg/); my $dec = $pla +net->dec(format => q/deg/); print qq/$name\t$ra\t$dec\n/}'
        Use Astro::Telescope to calculate the position in the sky from your location:
        #!/usr/bin/perl use strict; use warnings; use Time::Piece; use Astro::Coords; use Astro::Telescope; print qq/Planet\tAzimuth\t\t\tElevation\n/; for my $name (qw/Jupiter Saturn/) { my $planet = Astro::Coords->new(planet => $name); $planet->datetime(Time::Piece->new); $planet->telescope(Astro::Telescope->new( Name => q/1600 Pennsylvania Ave, Washington DC/, Long => -77, Lat => 38.9, Alt => 16.7)); my $az = $planet->az(format => 'deg'); my $el = $planet->el(format => 'deg'); print qq/$name\t$az\t $el\n/ }
        Output:
        Planet	Azimuth			Elevation
        Jupiter	132.670727106298	 -7.05306603251409
        Saturn	131.551952092501	 -7.04332546770451
        
        For sexagesimal notation omit the format parameter:
        #!/usr/bin/perl use strict; use warnings; use Time::Piece; use Astro::Coords; print qq/Planet\tRight Ascension\t\tDeclination\n/; for my $name (qw/Jupiter Saturn/) { my $planet = Astro::Coords->new(planet => $name); $planet->datetime(Time::Piece->new); my $ra = $planet->ra; my $dec = $planet->dec; print qq/$name\t$ra\t$dec\n/ }
        Output:
        Planet	Right Ascension		Declination
        Jupiter	20:00:56.326	-21:00:51.63
        Saturn	20:05:29.464	-20:41:17.35
        

        Very nice. Notice that we got different results. When I took Stellar Evolution, we were doing well to get within an order of magnitude with many first order approximations./p>

        $ ./1.astro.pl Planet Right Ascension Declination Jupiter 300.371015239225 -20.9886573993409 Saturn 301.438145819967 -20.6756490862067 $ cat 1.astro.pl #!/usr/bin/perl use strict; use warnings; use Time::Piece; use Astro::Coords; print qq/Planet\tRight Ascension\t\tDeclination\n/; for my $name (qw/Jupiter Saturn/) { my $planet = Astro::Coords->new(planet => $name); $planet->datetime(Time::Piece->new); my $ra = $planet->ra(format => q/deg/); my $dec = $planet->dec(format => q/deg/); print qq/$name\t$ra\t$dec\n/ } sleep 2; __END__ $

        We'll see where this folds into the ultimate product. Thanks for yor comments.

      Goal 3: I would start with the HTML (re: pulldowns etc), you probably require a form in order to sumbit user input to your back-end script. The back-end script can do the calculations and present them back to the webpage. Perhaps you can also present results by constructing an image on-the-fly via Perl (e.g. GD). I can see a bit of a problem when back-end processing takes some time to complete while the webpage says "waiting ...": timeouts, connection failures, exceeding web-host's CPU quota etc. can waste the backend processing and users retrying and clogging the system. I am not sure what a good system for that is: perhaps users submit jobs and when a job is completed an email/pdf is sent to them? Another idea is to add a database caching user requests. You may be able to save some processing this way (on the expense of setting+working a db).

      Can you, (or anyone), come up with with a mock-up of this?

      Also, I don't know how yet to have mojo projects that live longer than the terminal I have open with a daemon. How do I have a static url like mpj.com/perlmonks/conjunctions or mpj.com/perlmonks/conjunctions.html?

Re: calculating planet conjunction with mojo front end
by perlfan (Parson) on Dec 11, 2020 at 19:10 UTC
    marto's comments seem relevant. If you're familiar with Mojo, what's stopping you from creating a simple front end handler with required parameters, running your computations, then sending back the response in whatever form suits you?