Calculating apparent magnitude for comets and minor planets
See original GitHub issue(have edited this ticket to enhance the test program, update results and give a better explanation)
I have created a test program (see the end) to display the magnitude for a comet / minor planet both in PyEphem and Skyfield. Magnitude can be either absolute or apparent. I would like the apparent magnitude as, I believe, that is what one uses to determine whether an object is within viewing distance.
Running the test program yields:
PyEphem: 3.7.6.0
Skyfield: 1.33
PyEphem 88P/Howell
Magnitude (from PyEphem): 14.89
Earth Body Distance AU: 1.76101815700531
Apparent Magnitude (calculated): 14.89285058374846
Skyfield 88P/Howell
Absolute Magnitude (H from data file): 11.0
Earth Body Distance AU: 1.761017531999252
Apparent Magnitude (calculated): 11.987619922504665
PyEphem 1 Ceres
Magnitude (from PyEphem): 8.97
Absolute Magnitude (H from data file): 3.3399999141693115
Earth Body Distance AU: 2.8166115283966064
Apparent Magnitude (calculated): 8.967859508070683
Skyfield (1) Ceres
Absolute Magnitude (H from data file): 3.34
Earth Body Distance AU: 2.8166120923794224
Apparent Magnitude (calculated): 8.967860459749872
PyEphem uses different data formats for comets versus minor planets. Looking at each of the data formats, it appears the gk model is used for comets, whereas the HG model is used for minor planets. Both models are described here. I have have taken the formulae specified and put together two functions, one for each model (see test code below). Using Skyfield to load comet / minor planet data and compute their position, I then use my two functions to compute apparent magnitude. Using PyEphem, each object loaded, computed and the magnitude determined, but I also calculate my own absolute magnitude using the data.
Looking at the results:
-
For PyEphem for the comet 88P/Howell, the magnitude from PyEphem is 14.89 whereas what I have calculated (gk model) is 14.89285058374846. Suggest we have apparent magnitude and the values match.
-
For Skyfield for the comet 88P/Howell, the absolute magnitude is present in the data file (11.0). What I have calculated (HG model) is 11.987619922504665 which “feels right” as the comet is only a little more than 1AU away. Unfortunately this flies in the face of the PyEphem result! Not sure if this is a discrepancy between models, the data, my coding or what…
-
For PyEphem and Skyfield for the minor planet Ceres, whereas they use different data formats, each format contains the absolute magnitude 3.34. I suspect PyEphem uses the HG model (as does my Skyfield test) because both yield the same apparent magnitude of 8.97. Same formulae and same data values unsurprisingly yields same result…just cannot confirm the correctness!
In short, there is a discrepancy in the apparent magnitude for the comet between PyEphem and Skyfield, but the numbers match exactly (as expected) for the minor planet apparent magnitude between PyEphem and Skyfield.
Would like some feedback please if the calculation and logic is sound and I am more than happy for the code to be reused if anyone finds it useful.
The test program, adjust for the current date and ensure you obtain the latest data for the comet and minor planet. See the comments in the code.
#!/usr/bin/env python3
# Refer to https://github.com/skyfielders/python-skyfield/issues/416
# Download and save
# https://www.minorplanetcenter.net/iau/Ephemerides/Comets/Soft00Cmt.txt
# https://www.minorplanetcenter.net/iau/Ephemerides/Comets/Soft03Cmt.txt
# https://www.minorplanetcenter.net/iau/Ephemerides/Bright/2018/Soft00Bright.txt
# https://www.minorplanetcenter.net/iau/Ephemerides/Bright/2018/Soft03Bright.txt
# External verification:
# https://in-the-sky.org/data/object.php?id=0088P
# https://theskylive.com/88p-info
# https://heavens-above.com/comet.aspx?cid=88P
# https://www.calsky.com/cs.cgi/Comets/3?
import datetime, ephem, io, math, skyfield.api, skyfield.constants, skyfield.data.mpc
def pyephemCometMinorPlanet( utcNow, latitude, longitude, name, data, isComet ):
observer = ephem.Observer()
observer.date = ephem.Date( utcNow )
observer.lat = str( latitude )
observer.lon = str( longitude )
body = ephem.readdb( getData( name, data ) )
body.compute( observer )
sun = ephem.Sun()
sun.compute( observer )
if isComet:
apparentMagnitude = getApparentMagnitude_gk( body._g, body._k, body.earth_distance, body.sun_distance )
print( "PyEphem", name,
"\n\tMagnitude (from PyEphem):", body.mag,
"\n\tEarth Body Distance AU:", body.earth_distance,
"\n\tApparent Magnitude (calculated):", apparentMagnitude,
"\n" )
else:
apparentMagnitude = getApparentMagnitude_HG( body._H, body._G, body.earth_distance, body.sun_distance, sun.earth_distance )
print( "PyEphem", name,
"\n\tMagnitude (from PyEphem):", body.mag,
"\n\tAbsolute Magnitude (H from data file):", body._H,
"\n\tEarth Body Distance AU:", body.earth_distance,
"\n\tApparent Magnitude (calculated):", apparentMagnitude,
"\n" )
def skyfieldCometMinorPlanet( utcNow, latitude, longitude, name, data, isComet ):
timeScale = skyfield.api.load.timescale( builtin = True )
topos = skyfield.api.Topos( latitude_degrees = latitude, longitude_degrees = longitude )
ephemeris = skyfield.api.load( "de421.bsp" )
sun = ephemeris[ "sun" ]
earth = ephemeris[ "earth" ]
with io.BytesIO( getData( name, data ).encode() ) as f:
if isComet:
dataframe = skyfield.data.mpc.load_comets_dataframe( f ).set_index( "designation", drop = False )
body = sun + skyfield.data.mpc.comet_orbit( dataframe.loc[ name ], timeScale, skyfield.constants.GM_SUN_Pitjeva_2005_km3_s2 )
else:
dataframe = skyfield.data.mpc.load_mpcorb_dataframe( f ).set_index( "designation", drop = False )
body = sun + skyfield.data.mpc.mpcorb_orbit( dataframe.loc[ name ], timeScale, skyfield.constants.GM_SUN_Pitjeva_2005_km3_s2 )
t = timeScale.utc( utcNow.year, utcNow.month, utcNow.day, utcNow.hour, utcNow.minute, utcNow.second )
alt, az, earthSunDistance = ( earth + topos ).at( t ).observe( sun ).apparent().altaz()
ra, dec, sunBodyDistance = ( sun ).at( t ).observe( body ).radec()
alt, az, earthBodyDistance = ( earth + topos ).at( t ).observe( body ).apparent().altaz()
apparentMagnitude = getApparentMagnitude_HG( dataframe.loc[ name ][ "magnitude_H" ], dataframe.loc[ name ][ "magnitude_G" ], earthBodyDistance.au, sunBodyDistance.au, earthSunDistance.au )
print( "Skyfield", name,
"\n\tAbsolute Magnitude (H from data file):", dataframe.loc[ name ][ "magnitude_H" ],
"\n\tEarth Body Distance AU:", earthBodyDistance.au,
"\n\tApparent Magnitude (calculated):", apparentMagnitude,
"\n" )
# https://stackoverflow.com/a/30197797/2156453
def getData( orbitalElementName, orbitalElementData ):
return next( ( s for s in orbitalElementData if orbitalElementName in s ), None )
# https://www.clearskyinstitute.com/xephem/help/xephem.html#mozTocId564354
def getApparentMagnitude_gk( g_absoluteMagnitude, k_luminosityIndex, bodyEarthDistanceAU, bodySunDistanceAU ):
return g_absoluteMagnitude + \
5 * math.log10( bodyEarthDistanceAU ) + \
2.5 * k_luminosityIndex * math.log10( bodySunDistanceAU )
# Calculate apparent magnitude (returns None on error).
#
# https://www.clearskyinstitute.com/xephem/help/xephem.html#mozTocId564354
# https://www.britastro.org/asteroids/dymock4.pdf
def getApparentMagnitude_HG( H_absoluteMagnitude, G_slope, bodyEarthDistanceAU, bodySunDistanceAU, earthSunDistanceAU ):
beta = math.acos( \
( bodySunDistanceAU * bodySunDistanceAU + \
bodyEarthDistanceAU * bodyEarthDistanceAU - \
earthSunDistanceAU * earthSunDistanceAU ) / \
( 2 * bodySunDistanceAU * bodyEarthDistanceAU ) \
)
psi_t = math.exp( math.log( math.tan( beta / 2.0 ) ) * 0.63 )
Psi_1 = math.exp( -3.33 * psi_t )
psi_t = math.exp( math.log( math.tan( beta / 2.0 ) ) * 1.22 )
Psi_2 = math.exp( -1.87 * psi_t )
# Have found a combination of G_slope, Psi_1 and Psi_2 can lead to a negative value in the log calculation.
try:
apparentMagnitude = H_absoluteMagnitude + \
5.0 * math.log10( bodySunDistanceAU * bodyEarthDistanceAU ) - \
2.5 * math.log10( ( 1 - G_slope ) * Psi_1 + G_slope * Psi_2 )
except:
apparentMagnitude = None
return apparentMagnitude
utcNow = datetime.datetime.strptime( "2020-11-26", "%Y-%m-%d" )
latitude = -33
longitude = 151
print( "PyEphem:", ephem.__version__ )
print( "Skyfield:", skyfield.__version__ )
print()
with open( "Soft03Cmt.txt" ) as f:
orbitalElementData = f.readlines()
pyephemCometMinorPlanet( utcNow, latitude, longitude, "88P/Howell", orbitalElementData, True )
with open( "Soft00Cmt.txt" ) as f:
orbitalElementData = f.readlines()
skyfieldCometMinorPlanet( utcNow, latitude, longitude, "88P/Howell", orbitalElementData, True )
with open( "Soft03Bright.txt" ) as f:
orbitalElementData = f.readlines()
pyephemCometMinorPlanet( utcNow, latitude, longitude, "1 Ceres", orbitalElementData, False )
with open( "Soft00Bright.txt" ) as f:
orbitalElementData = f.readlines()
skyfieldCometMinorPlanet( utcNow, latitude, longitude, "(1) Ceres", orbitalElementData, False )
Issue Analytics
- State:
- Created 3 years ago
- Comments:10 (4 by maintainers)
Top GitHub Comments
I am glad we are now in agreement — and that your magnitude predictions come out correctly when the data file is interpreted as containing g/k parameters. I have just landed a commit (see the link right above this comment) to rename those two columns, so those should change with the next release of Skyfield (which will probably come within the next two weeks). I am trying to think of a way to also support code using the old names but I’m not sure there are many good options, and hopefully the columns are not widely used since they are not yet documented.
But if I think of a good way to support legacy code, I’ll follow up with a further commit.
@Bernmeister I use this function to calculate the magnitudes of comets for all calculation of magnitude at cobs.si and it seems to calculate magnitudes accurately so the k is not (2.5k) but just k
The g an k parameters in the MPC files are usually way off and the predictions out of those parameters are not the best. Since I have lot of comet observations in the cobs database I do a fit of g and k from the observations and use those parameters for the magnitude estimation.
You can also download the MPC file (in 1-line or ephem format) from cobs.si, but i would need to check if the g and k parameters in the output file are beeing substituted for the ones calculated by cobs.
Clear skies