cosinekitty / astronomy

Astronomy Engine: multi-language calculation of Sun, Moon, and planet positions. Predicts lunar phases, eclipses, transits, oppositions, conjunctions, equinoxes, solstices, rise/set times, and other events. Provides vector and angular coordinate transforms among equatorial, ecliptic, horizontal, and galactic orientations.
MIT License
452 stars 61 forks source link

Generalized physics simulator for asteroids and comets #207

Closed cosinekitty closed 2 years ago

cosinekitty commented 2 years ago

It would be nice to adapt the existing gravity integrator used for calculating Pluto's orbit to allow calculating the trajectory of asteroids, comets, coasting spacecraft, or other small bodies traveling ballistically through the Solar System. This would be focused on interplanetary movement, not satellites of any planet.

The caller will provide the state vector (position and velocity) of a small body. The StateVector objects also include a time value, which will be needed to calculate the state of the Sun and planets.

I need to think more about the details. Here are some ideas to ponder:

pakastin commented 2 years ago

Wow, cool! 🤩👌

cosinekitty commented 2 years ago

Here are some more thoughts on this. I'm mostly documenting for my own use. Also, I am thinking in terms of the C implementation. I usually start with C because it requires the most consideration of low-level concerns. Then the other languages tend to follow naturally.

Introduction

Unlike the existing C functions, this one requires memory allocation and deallocation, because (a) the structures are getting larger, and (b) I want to make an opaque data type to decouple outside callers with Astronomy Engine internals. I'm not trying to keep secrets; this is an open source project after all. The purpose is to leave the door open for changing my mind later on how to implement the internals, without breaking dependent code.

Implementation Plan

The following functions will be added:

This is the bare minimum of a useful gravity simulator. More features could be added later. The prime candidate I can think of so far is:

Testing and Validation

To verify the simulator is working correctly, I will use JPL Horizons to generate test data containing state vectors for major asteroids and/or comets. I would like a mix of asteroids with low-eccentricity orbits (like Ceres, Pallas, Vesta, and Juno) and a couple of comets having more eccentric orbits.

Limitations

This will not be the most general possible gravity simulator. It will be designed primarily for asteroids and comets that never pass very close to any planet. Therefore, it will not work for calculating planetary satellite orbits.

By default I will model gravitational effects of the Earth/Moon system by ignoring the Moon as a separate object and adding its mass to the Earth's mass.

In fact, there might be an option passed into GravSimInit that specifies whether the inner planets (Mercury, Venus, Earth, Mars) should be included at all. This would optimize execution speed for outer solar system bodies, with negligible effects on accuracy of the results.

In the future I could add another option to calculate the Earth and Moon separately. (Calculating the Moon's state vector is very time consuming.) So I will design the interface to allow for that option to be added later, without breaking the existing API. This would allow calculation of artificial satellite orbits or trajectories of Earth-grazing objects.

cosinekitty commented 2 years ago

A couple more notes about the gravity simulator design:

cosinekitty commented 2 years ago

Progress update

In the new gravsim branch, I have a prototype that simulates the movement of the asteroids Ceres, Pallas, Vesta, and Juno. It does so over a 20-year time span from 2020 to 2040, and compares the calculations with test data from JPL Horizons. The results are encouraging. There is less than 0.6 arcminutes of position error over that 20-year span.

Accuracy considerations

The 0.6 arcminutes of error persists no matter how small I make the time increment, which suggests that the error comes not from the finite time increment but from something else. My prime suspect is the fact that my planet position calculations are already approximated due to truncated VSOP87 series. If this is true, the most serious source of error would be Jupiter, which has more mass than all the other planets combined. Later today I will do an experiment to see if using more VSOP87 terms for Jupiter causes a decrease in the error for the asteroids. If so, it may be worth trading a modest increase in code size and execution time for better accuracy of the gravity simulator.

Another possible source of error is that even when I include the inner 4 planets (Mercury, Venus, Earth, Mars) in the gravity simulation, I do not use them to adjust wobble of the Sun (that is, the SSB). I have been assuming these planets are too small and too close to the Sun to matter. But I may also experiment with using them to refine the SSB position to see if that decreases error in asteroid positions.

Design change: multi-body simulation

Because I have to calculate the positions of the Sun and planets with respect to the Solar System Barycenter on each time step, I realized anyone who wanted to calculate more than one small body would be burdened with redundant calculations. Therefore, I changed the design to allow calculating any number of small bodies simultaneously with each simulation step. Once I add the additional method to retrieve the state vector for the Sun and planets from the simulator object, this will enable an efficient simulation of the entire Solar System, with as many additional bodies as desired.

Inconvenience of barycentric inputs/outputs?

To use the gravity simulator, the calling code must pass in the initial state of each body. This means you have to provide the position vector and velocity vector for each body. In the current design, these vectors are all with respect to the Solar System Barycenter (SSB). It occurs to me that this may be inconvenient for developers. If you have heliocentric coordinates, in order to convert them to barycentric coordinates, you would have to call HelioVector and pass it BODY_SSB to find the barycentric position of the Sun. Then you would have to add the Sun's barycentric vectors to the body's heliocentric vectors to obtain the body's barycentric vectors.

This is not so bad, but it is redundant, because the GravSimInit function already has to calculate the SSB.

So now I'm thinking it may be helpful to provide another parameter to the gravsim functions that specifies what coordinate system to use: barycentric, heliocentric, or geocentric. Then the inputs would be provided in the selected system, and the outputs would be reported in that same system. Not only will this be more efficient, it will simplify using the code when state vectors are known in a non-barycentric reference frame.

cosinekitty commented 2 years ago

Completed in b4f485eeccd0bf61c367a93ade78370710f71d0c