Determine coordinates at conjunction times - pyephem

The inferior conjunction of Venus today (while still being observable due to the northerly offset from the Sun) inspired the following research in pyEphem.
Determine the date when Venus has an inferior conjunction with the Sun. Is there a search function for (inferior) conjunctions between Venus and the Sun in pyEphem?
Determine the ecliptical latitude of Venus at the date. That should be easy.
Do this for conjunctions for the last 100 and next 100 years. That's just a loop.
I was wondering how to do this in pyEphem.
Thanks,
Gert

Doing it in PyEphem would be awkward because of the maneuvers necessary to reduce its return values to numbers ­— but it would look something like the following code, which instead uses the more modern Skyfield library for astronomy in Python. (This code also needs SciPy installed, so that its solver can be used to find the exact moment of conjunction:)
import scipy.optimize
from skyfield.api import load, pi, tau
ts = load.timescale()
eph = load('de421.bsp')
sun = eph['sun']
earth = eph['earth']
venus = eph['venus']
# Every month from year 2000 to 2050.
t = ts.utc(2000, range(12 * 50))
# Where in the sky were Venus and the Sun on those dates?
e = earth.at(t)
lat, lon, distance = e.observe(sun).ecliptic_latlon()
sl = lon.radians
lat, lon, distance = e.observe(venus).ecliptic_latlon()
vl = lon.radians
# Where was Venus relative to the Sun? Compute their difference in
# longitude, wrapping the value into the range [-pi, pi) to avoid
# the discontinuity when one or the other object reaches 360 degrees
# and flips back to 0 degrees.
relative_lon = (vl - sl + pi) % tau - pi
# Find where Venus passed from being ahead of the Sun to being behind.
conjunctions = (relative_lon >= 0)[:-1] & (relative_lon < 0)[1:]
# For each month that included a conjunction, ask SciPy exactly when
# the conjunction occurred.
def f(jd):
"Compute how far away in longitude Venus and the Sun are."
t = ts.tt(jd=jd)
e = earth.at(t)
lat, lon, distance = e.observe(sun).ecliptic_latlon()
sl = lon.radians
lat, lon, distance = e.observe(venus).ecliptic_latlon()
vl = lon.radians
relative_lon = (vl - sl + pi) % tau - pi
return relative_lon
for i in conjunctions.nonzero()[0]:
t0 = t[i]
t1 = t[i + 1]
print("Starting search at", t0.utc_jpl())
jd_conjunction = scipy.optimize.brentq(f, t[i].tt, t[i+1].tt)
print("Found conjunction:", ts.tt(jd=jd_conjunction).utc_jpl())
print()
Whichever astronomy library you use, that's the general approach to take: big steps forward through time (in this example, 1 month steps) looking for when Venus passes from being ahead of the Sun to behind it in longitude. Then, return to each of those months and zero in on the exact moment when their longitudes are the same. Here are a few values printed by the above script, which you can spot-check against published values from the USNO or other sources:
Starting search at A.D. 2013-Dec-24 00:00:00.0000 UT
Found conjunction: A.D. 2014-Jan-11 12:24:30.8031 UT
Starting search at A.D. 2015-Jul-28 00:00:00.0000 UT
Found conjunction: A.D. 2015-Aug-15 19:21:55.1672 UT
Starting search at A.D. 2017-Mar-01 00:00:00.0000 UT
Found conjunction: A.D. 2017-Mar-25 10:17:27.5276 UT
Starting search at A.D. 2018-Oct-03 00:00:00.0000 UT
Found conjunction: A.D. 2018-Oct-26 14:16:19.3941 UT
Starting search at A.D. 2020-May-06 00:00:00.0000 UT
Found conjunction: A.D. 2020-Jun-03 17:43:37.7391 UT

Related

How to find the local horizon longitude of the highest point of the ecliptic

I would like to use pyephem or skyfield to find the degree of the local horizon (starting from South = 0°) at which is located the highest point of the ecliptic. Note that I am not trying to find the culmination of a planet. It could well be that, when looking South, there is no planet on the ecliptic by that time/latitude, but there will still be a highest point of the ecliptic. Can anyone help?
While it’s likely that someone will soon jump in with a closed-form solution that uses spherical trigonometry — in which case it’s likely that Skyfield or PyEphem will only be used to determine the Earth orientation — here’s a quick way to get an answer within about a degree:
Generate the ecliptic as 360 points one degree apart across the sky.
Compute the altitude and azimuth of each one.
Choose the highest.
The result agrees closely to what I see if I open Stellarium, turn on the ecliptic, and choose a field star right near the point where the ecliptic reaches the highest point in the sky.
import numpy as np
from skyfield import api, framelib
from skyfield.positionlib import Apparent
𝜏 = api.tau
ts = api.load.timescale()
eph = api.load('de421.bsp')
bluffton = api.Topos('40.74 N', '84.11 W')
t = ts.utc(2021, 2, 16, 22, 52)
angle = np.arange(360) / 360.0 * 𝜏
zero = angle * 0.0
f = framelib.ecliptic_frame
d = api.Distance([np.sin(angle), np.cos(angle), zero])
v = api.Velocity([zero, zero, zero])
p = Apparent.from_time_and_frame_vectors(t, f, d, v)
p.center = bluffton
alt, az, distance = p.altaz()
i = np.argmax(alt.degrees) # Which of the 360 points has highest altitude?
print('Altitude of highest point on ecliptic:', alt.degrees[i])
print('Azimuth of highest point on ecliptic:', az.degrees[i])
The result:
Altitude of highest point on ecliptic: 67.5477569215633
Azimuth of highest point on ecliptic: 163.42529398930515
This is probably a computationally expensive enough approach that it won’t interest you once you or someone else does the spherical trigonometry to find an equation for the azimuth; but at the very least this might provide numbers to check possible formulae against.

mean and SD of directions (in degrees) in NetLogo

I'm working on a model in NetLogo where I would like to report the mean and standard deviation of a set of turtle dispersal directions (bearings from 0-360 degrees) in each year of the simulation. Of course there's no default command in NetLogo for these circular statistics, so I'll need to write out the calculations by hand. I'm wondering if anyone has worked out a similar custom function in NetLogo before?
I've come across this set of code for calculating the mean:
to-report mean-of-headings [headings]
let x-mean mean map [sin ?] headings
let y-mean mean map [cos ?] headings
if x-mean = 0 and y-mean = 0 [ report random 360 ]
report atan x-mean y-mean
end
But I'm not positive if that will do for the mean, and haven't seen code for the SD. My thought was to translate this R code into NetLogo language, and create a reporter similar to the one above?
Tester <-c(340, 360, 20) # list of bearings
sine = sum(sin(Tester * pi/180)) # sin of each angle, convert to radian first
cosine = sum(cos(Tester * pi/180)) # cos of each angle, convert to radian first
Tester_mean = (atan2(sine, cosine) * 180/pi) %% 360
mu = (Tester - Tester_mean + 180) %% 360 - 180 # Difference of each angle from mean
Tester_sd = sqrt(sum(mu^2)/(length(Tester) - 1)) # Standard Deviation
Tester_mean # mean bearing
Tester_sd # sd bearing

Confusion with using dec/ra to compute sub-lunar location

I have a need to compute the apparent azimuth and elevation angles as well as the sub-lunar lat/lon for a given date/time. The az/el angles I get generally agree with other sources (MoonCalc.org, Horizons, etc.) but there are not good comparison sources for the sub-lunar lat/lon. More importantly, I doubt the lat/lon I get using the dec/ra values because the ra barely changes over long time frames.
Here is the basic call I am making:
roc.date='2018/1/1 01:00:00'
moon=ephem.Moon(roc)
print('rocMoonTest: %s UTC-4, lat/lon = %0.4f [+N], %0.4f [+E]' %
(roc.date, math.degrees(roc.lat), math.degrees(roc.lon)))
print('Moon dec/ra = %s [+N], %s [+W]' % (moon.dec, moon.ra ))
print('Moon a_dec/a_ra = %s [+N], %s [+W]' % (moon.a_dec, moon.a_ra ))
print('Moon g_dec/g_ra = %s [+N], %s [+W]' % (moon.g_dec, moon.g_ra ))
print('Moon az/el = %0.4f, %0.4f' %
(math.degrees(moon.az), math.degrees(moon.alt)))
And then I iterate on that every 3 hours. Below is the output:
rocMoonTest: 2018/1/1 01:00:00 UTC-4, lat/lon = 43.0000 [+N], -78.0000 [+E]
Moon dec/ra = 18:53:07.1 [+N], 5:43:03.33 [+W]
Moon a_dec/a_ra = 19:22:21.3 [+N], 5:39:38.43 [+W]
Moon g_dec/g_ra = 19:22:44.7 [+N], 5:40:41.41 [+W]
Moon az/el = 105.3953, 43.0670
rocMoonTest: 2018/1/1 04:00:00 UTC-4, lat/lon = 43.0000 [+N], -78.0000 [+E]
Moon dec/ra = 19:07:55.4 [+N], 5:49:00.24 [+W]
Moon a_dec/a_ra = 19:32:24.2 [+N], 5:47:42.22 [+W]
Moon g_dec/g_ra = 19:32:35.1 [+N], 5:48:45.29 [+W]
Moon az/el = 169.5907, 65.8406
rocMoonTest: 2018/1/1 07:00:00 UTC-4, lat/lon = 43.0000 [+N], -78.0000 [+E]
Moon dec/ra = 19:13:15.7 [+N], 5:54:49.89 [+W]
Moon a_dec/a_ra = 19:41:07.2 [+N], 5:55:47.50 [+W]
Moon g_dec/g_ra = 19:41:05.5 [+N], 5:56:50.65 [+W]
Moon az/el = 246.5737, 49.4664
As expected and as verified by the az/el angles, the moon swings from East to West as the earth rotates and reaches a peak altitude somewhere during the period. However, none of the various dec/ra values change significantly. Over this 6 hour span, I would expect to see approximately a 6 hour change in the ra. Obviously, when I use any of these ra values to compute the longitude, I get the wrong answer. It appears the reference frame for dev/ra is not rotating with the earth. However, the docs indicate that I should expect it to.
Anyone care to explain where I went wrong in my understanding of the various right ascension variables and what the most direct way is to compute the sub-lunar lat/lon? Note, I would rather avoid using an approach that rotates the apparent az/el position into geodetic lat/lon.
The measurement “Right Ascension" is made not against the rotating surface of the Earth, but against the fixed stars of the sky — it is a kind of longitude but whose origin is the point on a star chart where the two great “equators of the sky,” the Earth’s equator and the “Solar System's equator”, the Ecliptic (which is not truly the Solar System equator because it's the plane of the Earth's orbit, rather than the weighted average of all planetary orbits), cross.
Since the point of their crossing itself moves as the ages pass, the system of Right Ascension is very slightly different every year, and very different across centuries and millenia. So Right Ascension and declination (celestial latitude) always have to be specified relative to some date, some exact moment like B1950 or J2000.
There is now a fixed coordinate system for RA and dec that doesn't move, the ICRS, which is oriented like J2000 but is defined using the positions of quasars which (we assume) won't move measurably within the lifetime of our species.
regarding this part of your question
what the most direct way is to compute the sub-lunar lat/lon?
Here is my code to calculate the sublunar point.
greenwich = ephem.Observer()
greenwich.lat = "0"
greenwich.lon = "0"
greenwich.date = datetime.utcnow()
#add Moon Sub Solar Point
moon = ephem.Moon(greenwich)
moon.compute(greenwich.date)
moon_lon = math.degrees(moon.ra - greenwich.sidereal_time() )
# map longitude value from -180 to +180
if moon_lon < -180.0 :
moon_lon = 360.0 + moon_lon
elif moon_lon > 180.0 :
moon_lon = moon_lon - 360.0
moon_lat = math.degrees(moon.dec)
print "moon Lon:",moon_lon, "Lat:",moon_lat
Hope that helps. I also use the same approach to calculate the sub-solar point. Works great for me.
EDIT: Yes... latitude of Greenwich is set to zero BECAUSE it doesn't matter at all for this calculation.
You might reinforce your thinking in the direction of this approach by taking a look at this other link:
Computing sub-solar point
Which gives basically the same solution, but for the sub_solar_point, also from Liam Kennedy (where he gave a non zero Lat for Greenwich), and also with an answer from Brandon Rhodes who wrapped the xephem library in python to give us pyephem, and until recently was actively maintaining it. Brandon is now focusing more on his next iteration, a pure python library called skyfield, which uses the latest available ephemeris with a more intuitive API.
https://pypi.org/project/skyfield/
https://rhodesmill.org/skyfield/installation.html
Although I can not contribute it now, might I suggest a comparison of the results of pyephem and skyfield, perhaps in a matplotlib figure or two, IOW, just how different/improved might be the results from skyfield?

Longitude formatting/scale for calculating distance with geopy

I am using geopy to simply calculate the distance between two long,lat co-ordinates.
However I am confused on what scale the longitude should be on.
The latitude co-ordinated go from -90 to +90, and currently I've put my Longitude on a scale from 0-360 degrees - should this be -180 to 180 to satisfy :
great_circle(NYC, test).miles
where NYC and test are the co-ord pairs.
Thanks,
Izzy
Geopy Point latitude must be in range [-90; 90], longitude should be in range [-180; 180].
Longitude is automatically normalized (e.g. 185 is normalized to -175), while out-of-band latitudes would result in a ValueError being thrown. See the Point normalization testcases for getting the better idea on how normalization works: test/test_point.py
An example from docs for calculating distance between two points:
>>> from geopy import distance
>>> newport_ri = (41.49008, -71.312796)
>>> cleveland_oh = (41.499498, -81.695391)
>>> print(distance.distance(newport_ri, cleveland_oh).miles)
538.39044536

Ecliptic coordinates of an Observer in PyEphem

I would like to have the ecliptic coordinates of a point on Earth. I can set up an observer using Pyephem:
station = ephem.Observer()
station.lon = '14:18:40.7'
station.lat = '48:19:14.0'
station.pressure = 0
station.epoch = ephem.J2000
station.elevation = 100.0
Then setup a date
station.date = ephem.date(datetime.utcnow())
But I don't know how to get this point coordinates in the Ecliptic system. If I try the Ecliptic function on the station Object it fails. Is there a way to do that in PyEphem?
If by “the ecliptic coordinates of a point on Earth” you mean “the ecliptic latitude and longitude which are overhead for a point on Earth,” then you might be able to generate a correct position by asking for the RA and declination of the point in the sky directly overhead for the location — where “directly overhead” is expressed astronomically as “at 90° altitude in the sky.” You would follow your code above with something like:
ra, dec = station.radec_of('0', '90')
ec = ephem.Ecliptic(ra, dec)
print 'Ecliptic latitude:', ec.lat
print 'Ecliptic longitude:', ec.lon
Try this technique out and see whether it returns a value anything like what you are expecting!