question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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:closed
  • Created 3 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
brandon-rhodescommented, Nov 29, 2020

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.

0reactions
jurezakrajsekcommented, Jun 17, 2022

@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

def obj_magnitude(self):
    r = self.comet_obj.distance()
    ra, dec, delta = self.observed_comet.radec()
    mag_g = self.row.magnitude_g
    mag_k = self.row.magnitude_k

    if self.num > 1:
        return np.asarray(
            [mag_g + 5 * math.log10(di) + 2.5 * mag_k * math.log10(ri) for ri, di in zip(r.au, delta.au)])
    else:
        return mag_g + 5 * math.log10(delta.au) + 2.5 * mag_k * math.log10(r.au)

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

Read more comments on GitHub >

github_iconTop Results From Across the Web

Apparent magnitude - Wikipedia
Apparent magnitude (m) is a measure of the brightness of a star or other astronomical object observed from Earth. An object's apparent magnitude...
Read more >
Conversion of Absolute Magnitude to Diameter - SFA Physics
Conversion of Absolute Magnitude to Diameter for Minor Planets. H = Absolute Magnitude: p = Asteroid Albedo: D = Size Estimate: kilometers.
Read more >
Cometary Absolute Magnitudes, their Significance and ...
The magnitude distribution index, a, of a cometary population is usually defined by the equation C = baH (9) where C is the...
Read more >
tut35-Magnitudes.pdf - Asterism.org
There are specific procedures for calculating absolute magnitudes of asteroids, comets, and meteors. Factors such as color, albedo, and phase angles must, ...
Read more >
asteroids - Calculating the luminosity of a comet
The visible coma and tail of a comet can be huge (if highly diffuse); 10^5 times or more the size of the nucleus....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found