Blog

Find next Mars/Jupiter/Saturn retrograde

This Stellarium script will find the next time Mars, Jupiter, and Saturn all retrograde at the same time.

// ******************************************************************************************
// Stellarium script to quickly determine when Mars is retrograding between Jupiter and
// Saturn, while they, themselves, are retrograding. It is brain-dead boring tedium,
// watching the screen for long periods to 'notice' this event. Stellarium's scripting
// takes the tedium out of the effort.
//
// Created by David O'Neil, Aug, 2019. Released to the public domain, for anyone interested.
// Just leave this 'created by' (or 'originally created by') verbage in the derived work.
//
// To use:
//   * set the date via Stellarium's user interface
//   * set the 'daysToAdvance' variable to whatever day step you want. Too big of a step may
//     cause you to miss the retrograde event.
//   * You might want to change the 'core.wait(0.03);' line to another number, based on your
//     computer's capabilities. You will know quickly enough, because no matter what start
//     date you set, the script will never advance more than one step because Stellarium is
//     retrieving the old values in it's 'getObjectInfo' routines.
// ******************************************************************************************


//Setup and global variables:
core.selectObjectByName("Mars", false);
//core.selectObjectByName("Saturn", false);
StelMovementMgr.setFlagTracking(true);

daysToAdvance = -5;   //Can be positive or negative. Change to your purposes.

daysToAdvanceString = "";  //Stellarium doesn't re-zero things on subsequent runs.
if (daysToAdvance > 0) daysToAdvanceString = "+";
//else daysToAdvanceString = "-";   //not needed. Script core keeps as '-5'
daysToAdvanceString = daysToAdvanceString + daysToAdvance + " days";

//core.debug(daysToAdvanceString);

saturnRA = core.getObjectInfo("Saturn").ra;
jupiterRA = core.getObjectInfo("Jupiter").ra;
marsRA = core.getObjectInfo("Mars").ra;

if (daysToAdvance > 0) {
   saturnDirection = 1.0;
   jupiterDirection = 1.0;
   marsDirection = 1.0;
   }
else {
   saturnDirection = -1.0;
   jupiterDirection = -1.0;
   marsDirection = -1.0;
   }

core.setGuiVisible (false);

findNextPushingPillarsEvent();

// ******************************************************************************************
//That is the end of this script.
// ******************************************************************************************


//The following are the functions used in this script:

function findNextPushingPillarsEvent() {
   if (daysToAdvance > 0) moveForward();
   else moveBackward();
   }


function moveForward() {
   allThreeMovingBackWithMarsBetween = false;
   marsIsGreatestDiff = false;

   while (!allThreeMovingBackWithMarsBetween) {
      core.setDate(daysToAdvanceString);
      core.wait(0.03);

      newSaturnRA = core.getObjectInfo("Saturn").ra;
      saturnDirection = newSaturnRA - saturnRA;
      if (saturnDirection < -350) {
         saturnDirection = 360 - saturnDirection;
         }

      newJupiterRA = core.getObjectInfo("Jupiter").ra;
      jupiterDirection = newJupiterRA - jupiterRA;
      if (jupiterDirection < -350) {
         jupiterDirection = 360 - jupiterDirection;
         }

      newMarsRA = core.getObjectInfo("Mars").ra;
      marsDirection = newMarsRA - marsRA;
      if (marsDirection < -350) {
         marsDirection = 360 - marsDirection;
         }

      saturnRA = newSaturnRA;
      jupiterRA = newJupiterRA;
      marsRA = newMarsRA;
      //core.debug("S: " + saturnDirection);
      //core.debug("J: " + jupiterDirection);
      //core.debug("M: " + marsDirection);
      if (marsDirection < 0.0 && saturnDirection < 0.0 && jupiterDirection < 0.0) {
         allThreeMovingBackWithMarsBetween = true;
         }
      if (allThreeMovingBackWithMarsBetween) {
         jupSatDiff = Math.abs(newSaturnRA - newJupiterRA);
         if (jupSatDiff > 180) jupSatDiff = 360 - jupSatDiff;
         //core.debug(jupSatDiff);
         marsSatDiff = Math.abs(newSaturnRA - newMarsRA);
         if (marsSatDiff > 180) marsSatDiff = 360 - marsSatDiff;
         //core.debug(marsSatDiff);
         marsJupDiff = Math.abs(newJupiterRA - newMarsRA);
         if (marsJupDiff > 180) marsJupDiff = 360 - marsJupDiff;
         //core.debug(marsJupDiff);
         
         if ((marsJupDiff > jupSatDiff) || (marsSatDiff > jupSatDiff)) {
            //core.debug("Entered!");
            marsIsGreatestDiff = true;
            allThreeMovingBackWithMarsBetween = false;
            }
         }
      }
   }
   

function moveBackward() {
   allThreeMovingForwardWithMarsBetween = false;
   marsIsGreatestDiff = false;

   while (!allThreeMovingForwardWithMarsBetween) {
      core.setDate(daysToAdvanceString);
      core.wait(0.03);

      newSaturnRA = core.getObjectInfo("Saturn").ra;
      saturnDirection = newSaturnRA - saturnRA;
      if (saturnDirection > 350) {
         saturnDirection = 360 - saturnDirection;
         }

      newJupiterRA = core.getObjectInfo("Jupiter").ra;
      jupiterDirection = newJupiterRA - jupiterRA;
      if (jupiterDirection > 350) {
         jupiterDirection = 360 - jupiterDirection;
         }
         
      newMarsRA = core.getObjectInfo("Mars").ra;
      marsDirection = newMarsRA - marsRA;
      if (marsDirection > 350) {
         marsDirection = 360 - marsDirection;
         }
         
      saturnRA = newSaturnRA;
      jupiterRA = newJupiterRA;
      marsRA = newMarsRA;

      // core.debug("saturnRA: " + saturnRA);
      // core.debug("newSaturnRA: " + newSaturnRA);
      //core.debug("saturnDirection: " + saturnDirection);
      
      if (marsDirection > 0.0 && saturnDirection > 0.0 && jupiterDirection > 0.0) {
         allThreeMovingForwardWithMarsBetween = true;
         }
      if (allThreeMovingForwardWithMarsBetween) {
         jupSatDiff = Math.abs(newSaturnRA - newJupiterRA);
         if (jupSatDiff > 180) jupSatDiff = 360 - jupSatDiff;
         //core.debug(jupSatDiff);
         marsSatDiff = Math.abs(newSaturnRA - newMarsRA);
         if (marsSatDiff > 180) marsSatDiff = 360 - marsSatDiff;
         //core.debug(marsSatDiff);
         marsJupDiff = Math.abs(newJupiterRA - newMarsRA);
         if (marsJupDiff > 180) marsJupDiff = 360 - marsJupDiff;
         //core.debug(marsJupDiff);
         
         if ((marsJupDiff > jupSatDiff) || (marsSatDiff > jupSatDiff)) {
            //core.debug("Entered!");
            marsIsGreatestDiff = true;
            allThreeMovingForwardWithMarsBetween = false;
            }
         }
      }
   }

Find next nearest separation script

This Stellarium script will find the next time two celestial objects are closest together. It is useful for finding when two planets conjunct or when a planet is close to a celestial object. If two planets are selected, and one of them starts retrograding before their conjunction, that will be the point of closest separation.

// ******************************************************************************************
// Stellarium script to find the next nearest time two objects are closest to each other.
// The time can be in the past or future, depending on whether they are initially moving
// away from each other.
//
// Created by David O'Neil, Aug, 2019. Released to the public domain, for anyone interested.
// Just leave this 'created by' (or 'originally created by') verbage in the derived work.
//
// To use:
//   * Set the 'obj1' and 'obj2' variables to whatever you want.
//   * Set the date via Stellarium's user interface close to a time you are looking for them
//     to come together.
//     (The date must be 1/2 year or so of a conjunction, to overcome the difficulty of
//     taking retrograde motions into account.)
//   * Run the script. It will find the next point of nearness that is closest to that date,
//     whether that is in the future or the past.
// ******************************************************************************************

pi = Math.PI;
degToRad = pi/180;

obj1 = "Jupiter";
obj2 = "Saturn";

core.selectObjectByName(obj1, true);
StelMovementMgr.setFlagTracking(true);

justFindSeparation = false;
if (justFindSeparation) {
   d = getRadiansBetweenObjects();
   d = d/degToRad;
   core.debug(d);
   degrees = Math.floor(d);
   minutes = d - degrees;
   minutes = minutes * 60;
   seconds = minutes - Math.floor(minutes);
   core.debug(degrees + " " + Math.floor(minutes) + " " + seconds*60);
   }
else findClosestConjunction();
core.debug(d / degToRad);


function findClosestConjunction() {
   core.selectObjectByName("obj1", true);
   core.setTimeRate(0); //Lock the sky in place, so we can see it unmoving!

   //Get the initial 2 points:
   a1 = getRadiansBetweenObjects();

   //Do initial iteration in 1-day increment:
   a2 = getTheAngleAfter("+1 days");

   direction = "+";
   if (a2 < a1) {
      direction = "+";
      }
   else {
      direction = "-";
      a2 = getTheAngleAfter("-1 days");
      a2 = getTheAngleAfter("-1 days");   //Don't know why can't use "-2 days" reliably!
      }
      
   timeStepString = direction + "1 days";

   //Iterate:
   while (a2 < a1) {
      a1 = a2;
      a2 = getTheAngleAfter(timeStepString);
      }
      
   //Assume we've gone through several days, and have passed the last good one,
   //so step back (or forward) a day to fix the overstep:
   if (direction == "+") {
      a1 = getTheAngleAfter("-1 days");
      }
   else {
      a1 = getTheAngleAfter("+1 days");
      }
      
      
   //Now we are doing it by the hours. As before, we must check whether we need to
   //go back or forward.

   //Now determine whether to go forward or back:
   a2 = getTheAngleAfter("+1 hour");

   if (a2 < a1) {
      direction = "+";
      }
   else {
      direction = "-";
      a2 = getTheAngleAfter("-1 hours");
      a2 = getTheAngleAfter("-1 hours");  //As before, don't know why can't just -2 this.
      }

   timeStepString = direction + "1 hour";

   while (a2 < a1) {
      a1 = a2;
      a2 = getTheAngleAfter(timeStepString);
      }

   //Assume we've gone through several hours, and have passed the last good one,
   //so step back (or forward) an hour to fix the overstep:
   if (direction == "+") {
      a1 = getTheAngleAfter("-1 hours");
      }
   else {
      a1 = getTheAngleAfter("+1 hours");
      }
      

   //And finally, for the minutes:
   //First, set a1 to a2, as a2 was last measurement taken at current time:
   a1 = a2;
   a2 = getTheAngleAfter("+1 minute");

   if (a2 < a1) {
      direction = "+";
      }
   else {
      direction = "-";
      a2 = getTheAngleAfter("-1 minutes");
      a2 = getTheAngleAfter("-1 minutes");
      }

   timeStepString = direction + "1 minute";

   while (a2 < a1) {
      a1 = a2;
      a2 = getTheAngleAfter(timeStepString);
      }
      
   core.debug("Finished! Separation = " + a1 + ", " + a2);

   core.setTimeRate(0); //Lock the sky in place, so we can see it unmoving!
   }


function getTheAngleAfter(timeStep) {
   obj2Azi = core.getObjectInfo(obj2).azimuth;
   core.setDate(timeStep);
   //The following was an attempt to leave the wait time at 0.01, and loop wait until
   //Stellarium got things caught up, but it never worked, and I had to change the
   //wait time to 0.05 many times, instead of 0.03.
   while (core.getObjectInfo(obj2).azimuth == obj2Azi) {
      core.wait(0.01);
      }
   angleDiff = getRadiansBetweenObjects();
   return angleDiff;
   }


function getRadiansBetweenObjects() {
   obj2Azi = core.getObjectInfo(obj2).elong;
   obj2Azi = obj2Azi * degToRad;
   obj2Alt = core.getObjectInfo(obj2).elat;
   obj2Alt = obj2Alt * degToRad;

   obj1Azi = core.getObjectInfo(obj1).elong;
   obj1Azi = obj1Azi * degToRad;
   obj1Alt = core.getObjectInfo(obj1).elat;
   obj1Alt = obj1Alt * degToRad;


   d = Math.acos(Math.sin(obj2Alt)*Math.sin(obj1Alt)+Math.cos(obj2Alt)*Math.cos(obj1Alt)*Math.cos(obj2Azi-obj1Azi));
   
   //The following formula is for when the objects are very close together, or very close to 180 degrees apart:
   //I may have Azi and Alt mixed up.
   
   // delAzi = obj1Azi - obj2Azi;
   // delAlt = obj1Alt - obj2Alt;

   //d = sqrt ( (cos(aziA-aziB) * (altA-altB)) ^2 + (aziA-aziB)^2 )
   //d = Math.sqrt ( Math.cos(delAzi)*(delAlt) * Math.cos(delAzi)*(delAlt) + (delAzi)*(delAzi) );
   
   return d;   //In radians
   }

Step to specified sun depression script

This Stellarium script lets you specify the desired sun depression, morning or evening, to step to. It is useful for seeing how the stars appeared at civil, nautical, and astronomic dusk/dawn conditions, among other things.

// ******************************************************************************************
// Stellarium script to go to specified sun depression, either morning or evening,
// depending upon variable setting.
//
// Created by David O'Neil, Aug, 2019. Released to the public domain, for anyone interested.
// Just leave this 'created by' (or 'originally created by') verbage in the derived work.
//
// To use:
//   * Set the date via Stellarium's user interface
//   * Set 'gotoMorning' = true for morning viewing, false for evening
//   * You might want to change the 'core.wait(0.03);' line to another number, so
//     Stellarium has enough time to process and update before checking new positions.
//     This is dependent upon your computer's capabilities, since Stellarium does not
//     do things asynchronously for scripting.
//   * Run the script.
//   * You can change the year/month/day and Stellarium will automatically update
//     the time to the selected sun depression. Once it is finished getting to the time,
//     the selected object will be re-selected (the cross-hairs will reappear).
// ******************************************************************************************



objectToSelect = "Mars";   //SET THIS ONE (to "" if you want nothing selected)
gotoMorning = true;        //SET THIS ONE!
//gotoMorning = false;
desiredDepression = 18.0;  //AND SET THIS ONE! The next chart is useful:

GridLinesMgr.setFlagHorizonLine(true);
LandscapeMgr.setFlagCardinalsPoints(true);

//These are the arcus visionis values for the planets, and an estimation for Sirius:
//The planetary values were taken from the Planetary, Lunar, and Stellar Visibility computer
//program, version 3.1.0, 2006, by Rainer Lange and Noel M. Swerdlow. The newest version
//should be at http://www.alcyone.de/planetary_lunar_and_stellar_visibility.html.
//
// Inner Planets   Morning First       Morning Last       Evening First       Evening Last
//  Mercury            13.0°               9.5°               10.5°              11.0°
//  Venus               5.7°               6.0°                6.0°               5.2°
//
//                Heliacal Rising    Heliacal Setting   Acronychal Rising   Cosmical Setting
// Object            (Morning)          (Evening)           (Evening)          (Morning)
//  Mars               14.5°              13.2°                6.0°               6.0°
//
//  Jupiter             9.3°               7.4°                6.0°               6.0°
//
//  Saturn             13.0°              10.0°                8.0°               8.0°
//
//  Sirius              7.8°               6.5°                4.0°               4.0°
//
// In addition, Civil Dusk = 0 - 6°, Nautical = 6 - 12°, Astronomic = 12 - 18°

desiredDepression = -desiredDepression;   //Enter it positively, and switch to negative here.
sunAzimuth = core.getObjectInfo("Sun").azimuth;
sunAlt = core.getObjectInfo("Sun").altitude;
//A 'catch up' time for Stellarium to do its work before re-querying attributes
waitTime = 0.03;

if (sunAzimuth >= 180 && sunAzimuth <= 360 && gotoMorning) {   //180 - 360 = western sun
   //We need to shift by half day.
   core.setDate("-12 hours");
   }
else if (sunAzimuth >= 0 && sunAzimuth <= 180 && !gotoMorning) {  //eastern sun
   core.setDate("+12 hours");
   }

core.wait(waitTime);  //Let computer catch up.
sunAzimuth = core.getObjectInfo("Sun").azimuth;
sunAlt = core.getObjectInfo("Sun").altitude;

// We now have 4 conditions:
// 1 - looking for morning, sun above desired condition
// 2 - looking for morning, sun below desired condition
// 3 - looking for evening, sun above desired condition
// 4 - looking for evening, sun below desired condition.

// For 1 and 4, the sun needs to go backward with respect to its normal forward movement.
// But each case stands on its own, because one coming from below, the other from above.

//So we can loop the entire chain, so the user can change the date and Stellarium
//will automatically update when change is made

lastDate = "dummy start date";
core.wait(waitTime);
justFinishedProcessing = false;

while (true) {
   specifiedDate = core.getDate();
   if (justFinishedProcessing) {
      lastDate = specifiedDate;
      justFinishedProcessing = false;
      }
   if (specifiedDate != lastDate) {
      //Clear the crosshairs, so you can tell it is processing:
      core.selectObjectByName("", true);
      sunAlt = core.getObjectInfo("Sun").altitude;
      // Case 1:
      if (gotoMorning && sunAlt>desiredDepression) {
         //Go backward first:
         while (sunAlt>desiredDepression) {
            gotoTime("-10 minutes");
            }
         //Then forward:
         while (sunAlt<desiredDepression) {
            gotoTime("+1 minutes");
            }
         //You get the picture...
         while (sunAlt>desiredDepression) {
            gotoTime("-10 seconds");
            }
         while (sunAlt<desiredDepression) {
            gotoTime("+1 seconds");
            }
         while (sunAlt>desiredDepression) {
            gotoTime("-1 seconds");
            }
         sunAlt = desiredDepression;   //It has been done, so quit jimmying with it.
        }

      //Case 2, start at morning below
      else if (gotoMorning && sunAlt<desiredDepression) {
         //Go forward first:
         while (sunAlt<desiredDepression) {
            gotoTime("+10 minutes");
            }
         //Then backward:
         while (sunAlt>desiredDepression) {
            gotoTime("-1 minutes");
            }
         //You get the picture...
         while (sunAlt<desiredDepression) {
            gotoTime("+10 seconds");
            }
         while (sunAlt>desiredDepression) {
            gotoTime("-1 seconds");
            }
         sunAlt = desiredDepression;   //It has been done, so quit jimmying with it.
         }
         
      //Case 3, start at evening above
      else if (!gotoMorning && sunAlt>desiredDepression) {
         //Go forward first:
         while (sunAlt>desiredDepression) {
            gotoTime("+10 minutes");
            }
         //Then backward:
         while (sunAlt<desiredDepression) {
            gotoTime("-1 minutes");
            }
         //You get the picture...
         while (sunAlt>desiredDepression) {
            gotoTime("+10 seconds");
            }
         while (sunAlt<desiredDepression) {
            gotoTime("-1 seconds");
            }
          sunAlt = desiredDepression;   //It has been done, so quit jimmying with it.
        }

      //Case 4, start at evening below
      else if (!gotoMorning && sunAlt<desiredDepression) {
         //Go backward first:
         while (sunAlt<desiredDepression) {
            gotoTime("-10 minutes");
            }
         //Then forward:
         while (sunAlt>desiredDepression) {
            gotoTime("+1 minutes");
            }
         //You get the picture...
         while (sunAlt<desiredDepression) {
            gotoTime("-10 seconds");
            }
         while (sunAlt>desiredDepression) {
            gotoTime("+1 seconds");
            }
         sunAlt = desiredDepression;   //It has been done, so quit jimmying with it.
         }
      justFinishedProcessing = true;
      lastDate = specifiedDate;
      core.debug(sunAlt);
      
      //If you want to add a marker, for showing trajectory day-by-day:
      //alt = core.getObjectInfo(objectToSelect).altitude;
      //azi = core.getObjectInfo(objectToSelect).azimuth;
      //HighlightMgr.addPointAltAzi(alt, azi);
      //HighlightMgr.update(1440);
      //And later, to unhighlight it:
      //HighlightMgr.cleanHighlightList();
      // Unfortunately, highlights move with background, not stay at alt/azi!
      // To overcome this, you will need to store a list of alt/azi values, then
      // plot them at the end of a sequence.
      
      //Set the crosshairs again, to tell it is done processing:
      core.selectObjectByName(objectToSelect, true);
      core.wait(0.3);
      core.setTimeRate(0); //Lock the sky in place, so we can see it unmoving!
      }
   core.wait(0.1); //Allow the processor some rest.
   }
   

function gotoTime(time) {
   core.setDate(time);
   core.wait(waitTime);
   sunAlt = core.getObjectInfo("Sun").altitude;
   }

The Origin of the Celestial Lion

LEO IN 1500 BC

This is how Leo appeared shortly after sunset, about a month before the summer solstice in 1500 BC.

_____

One of the questions arising from my work is, “When were the stars in Leo first pictured as a lion?”

The most comprehensive historical resource I’ve seen is Gary David Thompson’s writings. He indicates that the earliest reference in Egypt is found in Senmut’s tomb, dating it to approximately 1500 BC. In Babylon, the earliest date is roughly the same: about 1530 BC. These are both before the time of the celestial interaction recorded in the Samson story.

As both constellations are linked to the same stars (A, B), the next question is, “How much historical interaction existed between these cultures during those times?” (And remember that Israel neighbored both these societies.) The Amarna Letters show the influence is more than one may first think, and the Samson story confirms the link.

Another question is “Why were they pictured as a lion?” Viewing the previous graphic, you can see that the stars do resemble a stick-figure lion. There may have been more at play in our ancestors’ minds. The following is conjectural, because I am not very familiar with lion habits, but according to rainfall and other sites, June was the beginning of the hot part of their year. (I haven’t seen any indication that their rainfall patterns have significantly changed in the last thirty-five hundred years.) Lions may have become more active at that time, although such isn’t mentioned on Wikipedia’s treatment. If you know more about lion habits in this regard, feel free to leave a comment.

The animation is derived from Stellarium, a wonderful open source planetarium program. Thank you, Fabian, and all those who helped out on that fantastic project!

Goose bumps to a cemetery

While putting the finishing touches on the 4th edition of Laughing at the Devil I wondered if ‘goose bumps’ should be hyphenated. A quick search revealed it shouldn’t, but, even more interestingly, I found the term once referred to sexually-transmitted diseases. The cause is said to be (for England and the associated Western civilization:) the bishop of Winchester licensed prostitutes outside of London, associating the symptoms of diseases linked to that profession to goose bumps. The term ‘Winchester goose’ became a permanent nickname for those poor ladies.

Several years ago an author seems to have been led to this history when one of his supposedly-fictional characters indicated she was buried in a cemetery not far from him. Today those thousands interred there are honored by the locals, as well as visitors from afar, who decorate the gates and graves, and celebrate the memory of the not-so-fortunate ones of previous times. Perhaps someday I will make that pilgrimage myself.

Web Programming

Welcome to a very dated ‘small slice of web programming’ page. This page contains some information you might find useful if you ever play with the nuts and bolts of web programming via PHP. It also contains a few SQL queries for WordPress sites you might find useful.

I’ve long since moved on to using WordPress without the low-level tinkering the first portion of this page contains, and I recommend it to you as well, as doing so will save a bunch of time in the long run.

One of the items I fought with back in that stone age Continue reading “Web Programming”

Nero Installation Tip

If you have a Samsung DVD recorder/player, and your install disk contains Nero Express 7 and is labeled “[BG68-01353A REV. 02],” do yourself a favor, and DON’T INSTALL IT! Well, do install it, but not the way you would normally think to do.

The engineers who created this disk and allowed it on the market should be ashamed of themselves! Installing the Nero suite is INCREDIBLY SLOW! Over the course of 30 minutes, it had only copied about thirty percent of the files to my drive.

Continue reading “Nero Installation Tip”

Creating an Index in MS Word

One of the major tasks while completing a book such as Laughing at the Devil is creating the index. If you don’t like drudgery, or are unsure what words to include, you might want to hire a professional. But if those ideas don’t scare you and you can figure out what searchers may really want to look up, the following will be helpful for MS Word users. (Seth Maislin’s tips at http://taxonomist.tripod.com/indexing/wordproblems.html will also be of assistance.) Continue reading “Creating an Index in MS Word”

Search Site / View Categories / View Tags

All content © 2005-present by David O'Neil