Cálculo de los planetas y lunas en base a la fuerza gravitatoria de Newton

Estoy tratando de entender cómo calcular las órbitas de los cuerpos del sistema solar en un marco de n-cuerpos, basado en la interacción gravitatoria por pares entre los objetos. Actualmente, estoy considerando 44 objetos (sol, planetas, lunas principales y asteroides principales).

Estoy comenzando con los vectores de estado (posición y velocidad) de cada uno de los objetos con el Sol como centro obtenidos de telnet ssd.jpl.nasa.gov 6775(JPL Horizons) el 01 de enero de 2017 a las 00:00 UTC y me gustaría dejar que el sistema evolucione durante 4344h, 01- Julio-2017 a las 00:00h.

He escrito un programa para hacer esto en Java, y hasta ahora los resultados no parecen estar ni siquiera razonablemente cerca de lo que deberían ser, en comparación con los vectores de estado obtenidos de Horizons. Después de cada paso de tiempo de 2 segundos, se calculan las fuerzas gravitatorias netas sobre cada cuerpo de todos los demás, y luego, de una sola vez, todas las velocidades y posiciones se actualizan en función de las aceleraciones de esas fuerzas netas. Luego comparo los vectores de posición actualizados finales de la aplicación con los datos obtenidos de Horizons después de corregir la posición actualizada del Sol.

La comparación muestra que las posiciones de la Tierra y los planetas exteriores tienen un error de posición de menos de 50 km (de hecho, los planetas más lejanos tienen menos de 10 km). Donde en cuanto a Mercurio el error es de 250 km. ¡Y las lunas de Júpiter y Saturno están desviadas entre 50 000 y 300 000 km!

En mi aplicación, no estoy diferenciando entre el Sol, los planetas y las lunas, por lo que no estoy seguro de por qué debería haber tantos más errores para las lunas. He intentado disminuir el tamaño del paso, de 2 segundos a 0,25 segundos, pero no hay una mejora significativa.

¿Cuáles podrían ser los problemas que debería investigar aquí? ¿Hay cosas que claramente necesitan mejorar de inmediato? ¿O tal vez hay pruebas que puedo hacer para ayudar a diagnosticar las principales fuentes de error?


EDITAR: Aquí está la esencia del método de cálculo solicitado en los comentarios:

while (nowT < endT) {
    doOneStep(step, nowT)
    nowT += stepT
}

allItemLinksson colecciones de ItemLink- enlaces entre objetos. en este caso Enlace de gravedad entre todos los pares de objetos. Para nlos objetos, habrá n.(n+1)/2enlaces .

doOneStep(double deltaT, double nowT){
    initForces fo all items to 0,0,0
    for each ItemLink **allItemLinks**)
        inf.evalForce(deltaT, false)
    updatePosAndVel(deltaT, nowT, true)
}

En ItemLink:

evalForce(double deltaT, boolean bFinal) {
    addGravityEffect(deltaT);
}

boolean addGravityEffect(double deltaT) {
    rVector = item2.pos - item1.pos
    double gF = G.mq.m2/r2
    fVector = gF in rVector direction
    item1.addForce(fVector)
    similarly for item2 to item1
}

allItemses una colección de objetos Item (Sol, planetas y lunas)

void updatePosAndVel(double deltaT, double nowT) {
    for each Item of **allItems** updatePandV(deltaT, nowT);
}

En artículo:

netForce, nowAcc, effectiveAcc, deltaV, newPos etc.son todos Vector3d

updatePAndV(double deltaT, double nowT, boolean bFinal){
        nowAcc = netForce / mass
        effectiveAcc = mean of lastAcc and nowAcc
        deltaV = effectiveAcc * deltaT
        meanV ...
        newPos = oldPos + meanV * deltaT
}

No trabaja en campos de gravitación sino con fuerzas directas debido a la gravedad entre objetos.

Con el código anterior, puedo obtener órbitas estables. Incluso los tiempos de órbita de las lunas son buenos. Consigue una buena configuración de Saturno con los movimientos cicloidales de las lunas y la configuración de Urano con el movimiento helicoidal de las lunas alrededor de Urano. No se como enviar archivos o imagenes para esta discusion

El desplazamiento de Mercurio sería correcto, debido a los efectos relativistas. Culparía de la inexactitud de las posiciones de las lunas a los errores de precisión numérica, especialmente porque interactúan mucho entre sí.
Además, si calcula su posición en relación con el Sol para Io, tiene un semieje mayor de 0,003 AU de radio orbital, a una distancia de 5,2 AU del Sol. Esto funciona mal con valores de coma flotante, ya que el gran desplazamiento fijo desde el centro del sistema de coordenadas les impide aumentar la precisión al cambiar la mantisa y los cambios ocurren en la cola lejana de la base con mucha precisión perdida detrás de su cola.
Esto es más un problema de CS. ¿Qué precisión estás usando? ¿Ha considerado Runge-Kutta y/o integradores simplécticos? Lo que tienes aquí es el problema de los n cuerpos. Es probable que el error del mercurio se deba a efectos relativistas.
No creo que la desviación de Mercurio en 250 km en siete días tenga nada que ver con la relatividad, ni tampoco con las lunas de Júpiter en 100.000 km. Las lunas tienen el peor error porque tienen el período más corto y, por lo tanto, son las que más cambian. Supongo que solo estás usando v i + 1 = v i + Δ t   F / metro ; X i + 1 = X i + Δ t   v i y nada más, pero no lo sabremos hasta que compartas más. Si quiere escribirlo usted mismo y no quiere usar un solucionador de biblioteca, RK4 o RK4 (5) son solo unas dos docenas de líneas más o menos.
Duración del cálculo en 6 meses (01 de enero de 2017 al 01 de julio de 2017).
Estoy codificando en Java con Vector3d (variables 'dobles'). Ante la sospecha de un problema de precisión, probé con Big Decimal (32 dígitos significativos) para las posiciones de Europa de Júpiter (solo un objeto con BigDecimal ya que lleva demasiado tiempo calcularlo). Aún así, el error para Europa fue muy grande, similar al cálculo anterior con 'doble'. No estoy usando ningún método de integración, solo adiciones numéricas, actualizando posiciones y velocidad cada 2 segundos.
¿Qué números está usando para la masa (o parámetros de masa)? También puede leer astronomy.stackexchange.com/questions/2416/…
Si no está utilizando al menos un integrador RK4 simple, siempre obtendrá respuestas completamente incorrectas. No es precisión, no es relatividad, solo está utilizando el Método de Euler que , al ser solo de primer orden , por sí solo ni siquiera le dará nada parecido a una órbita físicamente correcta. Solo eche un vistazo a la primera imagen en el artículo de Wikipedia i.stack.imgur.com/hfAv5.png Hasta que publique algunas ecuaciones o líneas de código en el cuerpo de su pregunta , realmente no puedo publicar una respuesta completa, pero El primer pedido no vale nada aquí.
O simplemente puede ver ¿Cómo resolver ODE con Java? . Esto muestra el uso del algoritmo Dopri853 (un orden superior, interpolación, tamaño de paso adaptativo RK) del solucionador Apache Commons ODE para planetas en Java. ¡Presta atención a la respuesta también!
@uhoh Gracias por mover mis datos adicionales a la pregunta principal.
@uhoh lo siento, hay un malentendido. Lo que quise decir es que obtengo órbitas ya que mencionaste que es posible que las órbitas no se cierren. Francamente, me emocioné cuando vi los movimientos cicloidales y helicoidales y me expresé en exceso. Parece que el enfoque básico puede ser correcto para los planetas, pero tiene problemas al manejar las lunas y ver si se requiere algún manejo especial cuando se está cerca de objetos masivos. Agradezco su respuesta muy activa y útil. Necesito ayuda para esto.
¡Bueno, ningún problema! He comenzado a eliminar algunos de los comentarios antiguos. ¡Creo que esta es una muy buena pregunta! Intentaré publicar una respuesta en uno o dos días, y probablemente otros también lo hagan. Debe usar una integración de orden superior que el método de Euler de primer orden que está describiendo, intentaré darle al menos dos opciones.
@SF. parece que tienes razón! Es necesario activar la Relatividad General para arreglar Mercurio. Hay un descentramiento cíclico durante cada órbita de unos cientos de kilómetros. Entendí mal el tiempo de integración (pensé que eran siete días) pero durante meses, es necesario. Publicaré los resultados de GR tan pronto como pueda hacer una trama bonita y obtener las matemáticas en MathJax.
@uhoh estoy de vuelta. Modifiqué mi código para RK4. es decir, para cada objeto se reposiciona con el método RK4. Durante el método RK4 para un objeto en particular, todos los demás objetos se mantienen en las ubicaciones del paso anterior. Al comparar los resultados (después de 6 meses desde 20170101) con Horizons, encuentro que el error es muy alto con pasos de 100, menor con pasos de 10. Incluso con un paso de 2s, los errores son 30 km de la Tierra, 17 km de Júpiter, menos de 3 km de las plantas exteriores. Pero Venus 50, Mercurio 240, Europa 120000, Io 330000 etc. Cualquier comentario. ¿Es con efecto relativista o efecto de gravedad con retardo de tiempo a la velocidad de la luz?
@vishu, la forma correcta de hacer la propagación de múltiples cuerpos es construir un solo vector con todas las variables de posición y velocidad . Entonces (como mencioné en mi respuesta) si hubiera dos cuerpos, usarías y = ( X 1 , y 1 , z 1 , X 2 , y 2 , z 2 , v X 1 , v y 1 , v z 1 , v X 2 , v y 2 , v z 2 ) que está Xen mi script de python, para norte cuerpos el vector tendrá longitud 6 norte . Todas las variables avanzan en paralelo en cada uno de los cuatro subpasos de cada iteración de la integración RK. También me mantendría alejado de las lunas de Júpiter hasta que agregue múltiplos gravitacionales de orden superior (por ejemplo, j 2 ) debido a la oblación.
No entendí 'múltiplos gravitacionales de orden superior (por ejemplo, J2)'
@uhoh de nuevo con todas las variables avanzadas en paralelo para cada subpaso de RK4. Ahora encuentro un error consistente con Horizon después de 6 meses desde 20170101 00:0. Lo que quiero decir es que el error para los planetas y las lunas principales todavía existe, pero casi sigue siendo el mismo con pasos de cálculo de 10, 100, 600 o incluso 1800. Pero con 1800, Phobos-Mars comienza a huir de Marte. Parece que el paso de 1800 es demasiado grande para Fobos con un período orbital muy corto. Mi conclusión, RK4 ha permitido aumentar el tiempo de paso (digamos 600 s), pero aún quedan errores, debido a otras razones además del paso de cálculo.
@vishu vale, ¡es una gran noticia! Compruebe que está utilizando los mejores valores para los parámetros gravitacionales estándar ( GRAMO veces METRO ), los últimos números del JPL se pueden encontrar en esta pregunta . Después de eso, hay dos grandes correcciones a la gravedad newtoniana simple de masa puntual a masa puntual que se me ocurren; 1. Relatividad General (GR) , y 2. multipolos gravitacionales de orden superior (p. ej. j 2 y más allá) y fuerzas de marea. Mercurio mostrará una gran mejora con GR, y la Tierra-Luna y las lunas de los planetas gigantes mostrarán una mejora con la gravedad no puntual.
@vishu verifique sus masas y actualizaré/agregaré una respuesta para la parte GR y algo para abordar j 2 . Dame un día más o menos.
Todos los valores de GM se toman de sd.jpl.nasa.gov/pub/xfr/gm_Horizons.pck. Gracias. Esperaré, no hay prisa.
Error de mi parte es ftp a 'ssd.jpl.nasa.gov/pub/xfr/gm_Horizons.pck'

Respuestas (2)

Aparte de los problemas numéricos, "Con el Sol como centro" puede ser parte de su problema. Obtenga todos los datos de Horizons en relación con el Baricentro del Sistema Solar, no el Sol, que se mueve en relación con el baricentro. Ese baricentro es un marco de referencia inercial, mientras que el centro del Sol no lo es. También asegúrese de colocar la posición inicial y la velocidad del Sol y dejar que se mueva, si aún no lo ha hecho.

¡Buen punto! Ni siquiera me di cuenta de eso.
Estoy tomando datos de horizontes con centro solar en 20170101 y dejo que los objetos reaccionen y se muevan. Inicialmente, la posición y la velocidad del Sol son ambas 000. Durante el cálculo, el Sol se mueve. Después de completar los cálculos hasta 20170701, todos los datos resultantes se modifican con respecto a la nueva posición y velocidad del Sol como base. Luego, esto se compara con los datos de Horizons para 20170701 nuevamente con Sun-center.
Lo que recomiendo es que obtenga todos sus datos relativos al Baricentro del Sistema Solar (@0). No el Sol (@ 10). Si lo haces correctamente, el Sol no tendrá una posición inicial y una velocidad de cero. Entonces no necesita cambiar de base a la nueva posición y velocidad del Sol al final.
Pero, ¿no es que el baricentro mismo depende de las posiciones relativas del planeta? Puedo entender que el baricentro Tierra-Luna está fijo en relación con la Tierra y la Luna. Pero con múltiples planetas, ¿no cambia con las posiciones de los planetas?
No. Ese es el objetivo de encontrar y usar el baricentro. Es el centro de masa de todos los cuerpos del sistema solar y, por conservación del momento, no se mueve en el marco de inercia de un sistema solar cerrado, independientemente de cómo se muevan los cuerpos del sistema solar.
@marca Gracias. Permítanme digerir eso primero (conservación del impulso y, por lo tanto, el centro no se mueve, por supuesto, considerando el sistema solar aislado). Probaré con datos con el baricentro del Sistema Solar. Mejorará (podría) la precisión de los planetas, pero el gran error de las lunas más pequeñas... Parece que tengo algún otro problema. Volverá
@mark Ejecuté los cálculos con datos de g@0 de Horizons y comparé los resultados finales con los datos de g@0 en la fecha de finalización. Los valores de error son exactamente los mismos que antes. Una ventaja principal es que no tengo que ajustar las posiciones finales y las velocidades para volver a centrar con la nueva posición del sol para comparar los resultados con los datos de g@10 en la fecha final. Por error de lunas pequeñas, estoy jugando con mi comprensión del tiempo de propagación de la gravedad y la dilatación del tiempo :). Déjeme ver ..
Es probable que tenga problemas numéricos o problemas de parámetros con las lunas. El movimiento de las lunas debe integrarse en relación con los cuerpos que orbitan, tratando a otros cuerpos como perturbaciones. En relación con su distancia al Sol, las lunas se mueven en pequeñas cantidades alrededor de su cuerpo principal. También necesitas tener GM precisos para todos los cuerpos. (Por lo general, puede encontrar ese tipo de datos en los encabezados de salida de Horizons).
Todos los valores de GM se toman de ssd.jpl.nasa.gov/pub/xfr/gm_Horizons.pck.
@MarkAdler ¿Cómo simular el movimiento del Sol? ¿Gravedad newtoniana por otros planetas?

Publicaré los métodos numéricos en esta respuesta y el cálculo completo del sistema solar (incluida la relatividad y los posibles efectos de la forma achatada del Sol) como una segunda respuesta. Hay demasiado para ponerlo todo en una respuesta.

El método que describe se parece al método de Euler o lo que se puede llamar el método Euler Forward . En cada paso de tiempo d t usted calcula todas las fuerzas y sus aceleraciones netas resultantes a , y luego simplemente incrementar las velocidades v por a d t y todas las posiciones X por v d t . Necesitas pasos de tiempo absurdamente pequeños para acercarte a esto. Usted mencionó 2 segundos y 250 milisegundos, un poco corto para las escalas de tiempo del sistema solar.

En el siguiente script, he escrito el método Euler Forward y otros dos métodos de orden bajo de Runge-Kutta , generalmente llamados RK2 y RK4. Para cada método, se calcula una órbita simplificada (falsa) de Mercurio alrededor de un Sol fijo durante 100 días, con un número de iteraciones que varía de 10 a 10 000. Además, para cada uno, uso el solucionador de la biblioteca SciPyodeint() con una tolerancia de precisión relativa de 1E-12 por paso. odeint es un contenedor de python lsodade la biblioteca FORTRAN odepack.

Puede ver que incluso RK4 está de acuerdo con odeint el nivel de metros después de 100 días si usa un paso de tiempo de aproximadamente 15 minutos, y el método Euler Forward (lo que usa) necesitará una cantidad absurda de pasos para siquiera acercarse a esto.

Las técnicas numéricas no son el único problema aquí, publicaré una segunda respuesta en unos días con el resto de lo que necesita. Puedo hacerlo bajo una pregunta separada en lugar de publicar dos respuestas a la misma pregunta .

Pero esto debería ayudarlo a comenzar a codificar RK4 en Java o buscar una biblioteca numérica de Java como la de Apache mencionada en los comentarios.

La forma estándar más sencilla de resolver un problema orbital usando un solucionador ODE es poner todas las coordenadas y velocidades cartesianas en un vector largo, llámelo y , y escribe una sola función para la derivada del tiempo:

y ˙ = F ( t , y )

Entonces, si tuvieras dos cuerpos y tres dimensiones, el vector y sería:

y = ( X 1 , y 1 , z 1 , X 2 , y 2 , z 2 , v X 1 , v y 1 , v z 1 , v X 2 , v y 2 , v z 2 )

teniendo seis elementos por cuerpo. el derivado de X 1 es v X 1 , y la derivada de v X 1 es la aceleración a X 1 debido a todos los otros cuerpos.

Digamos que tienes un cuerpo en una fuerza central con un parámetro gravitacional estándar GRAMO METRO . La tasa de cambio de posición es solo la velocidad,

d X d t = v

y la razón de cambio de la velocidad es la aceleración, debida a la fuerza;

d v d t = a = GRAMO METRO r r 3

Si tuviera varios cuerpos, el r sería la distancia entre pares de cuerpos y para cada cuerpo sumarías todos los demás como ya lo describiste.

Así que si escribiste F , podría ser:

F = ( v X , v y , v z , GRAMO METRO X / r 3 , GRAMO METRO y / r 3 , GRAMO METRO z / r 3 ) .

El método Euler Forward que creo que está utilizando simplemente itera

y i + 1 = h   F ( t , y i )

con pasos de tiempo de h . El método RK2 mejorado (que se muestra a continuación) se escribiría:

k 1 = F ( t , y i )
k 2 = F ( t + h 2 , y i + h 2 k 1 )
y i + 1 = y norte + h k 2

y el omnipresente método RK4 se escribe como

k 1 = F ( t , y i )
k 2 = F ( t + h 2 , y i + h 2 k 1 )
k 3 = F ( t + h 2 , y i + h 2 k 2 )
k 4 = F ( t + h , y i + k 3 )

y i + 1 = y norte + h ( k 1 + 2 k 2 + 2 k 3 + k 4 ) / 6

Aquí está la sección que muestra la similitud y las diferencias entre el método Euler Forward (el método Runge-Kutta más simple) y dos métodos RK de orden superior. Esto está escrito para mayor claridad, no para acelerar, obviamente.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

def deriv(t, X):

    x, v = X.reshape(2, -1)
    acc  = -GMs * x * ((x**2).sum())**-1.5

    return np.hstack((v, acc))

def derivv(X, t):
    return deriv(t, X) # historical reasons

def RK_all(F, t0, X0, n, h, method=None):

    hov2, hov6   = h/2.0, h/6.0
    t, X         = t0, X0
    answer, time = [], []

    answer.append(X)
    time.append(t)

    for i in range(n):
        k1 = F(t,        X            )
        k2 = F(t + hov2, X + hov2 * k1)
        k3 = F(t + hov2, X + hov2 * k2)
        k4 = F(t + h,    X + h    * k3)

        if   method == 'EulerFwd':
            X = X + h*k1        # X + h*F(t, X)

        elif method == 'RK2':
            X = X + h*k2

        elif method == 'RK4':
            X = X + hov6*(k1 + 2.*(k2+k3) + k4)

        else:
            pass

        t += h

        answer.append(X)
        time.append(t)

    return np.array(time), np.array(answer)

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint as ODEint

GMs = 1.327E+20 # approx

X0 = np.array([-2.094E+10,  4.303E+10,  5.412E+09,
               -5.328E+04, -2.011E+04,  3.243E+03]) # approx

methodnames = ['RK4', 'RK2', 'EulerFwd']
niterations = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000]

Time = 100*24*3600.  # total time

methdict = dict()

for methodname in methodnames:

    times, answers, ODEanswers, posdevs = [], [], [], []

    for n in niterations:

        h  = Time/float(n)
        t0 = 0.0

        time, answer    = RK_all(deriv, t0, X0, n, h, method=methodname)
        # recalculate using library ODE solver for same times, to compare
        ODEanswer, info = ODEint(derivv, X0, time,
                                 rtol=1E-12, full_output=True)
        posdev = np.sqrt((((answer - ODEanswer)[:,:3])**2).sum(axis=1))


        times.append(time)
        answers.append(answer)
        ODEanswers.append(ODEanswer)
        posdevs.append(posdev)

    methdict[methodname] = (times, answers, ODEanswers, posdevs)

if 1 == 1:
    plt.figure()
    for i, meth in enumerate(methodnames):
        plt.subplot(1, 3, i+1)
        for time, answer, ODEanswer, posdev in zip(*methdict[meth]):
            x, y, z = answer.T[:3]
            plt.plot(x, y)
        plt.ylim(-2.8E+11, 0.8E+11)
        plt.xlim(-1.2E+11, 0.8E+11)
        plt.title(meth, fontsize=16)
        plt.plot([0],[0], 'ok')
    plt.show()

if 1 == 1:
    plt.figure()
    for i, meth in enumerate(methodnames):
        plt.subplot(1, 3, i+1)
        for time, answer, ODEanswer, posdev in zip(*methdict[meth]):
            plt.plot(time/(24*3600.), posdev)
        plt.yscale('log')
        plt.ylim(1E-01, 1E+12)
        plt.title(meth+' vs odeint', fontsize=16)
    plt.suptitle('RKmethod - odeint (meters) vs time (days)', fontsize=18)
    plt.xticks([0, 20, 40, 60, 80, 100])
    plt.show()
@vishu Seguiré agregando a esto, si algo no está claro, deje un mensaje. Es una buena práctica para mí escribir todo esto, a veces explicar claramente puede ser un desafío. ¡ Cualquier otra persona , por favor, comente y sugiera mejoras en la claridad son bienvenidos!
@vishu ¿Esto parece útil? Agregando relatividad general a F corregirá el problema con Mercury y en realidad son solo unas pocas líneas más de código. Intentaré agregarlo de alguna manera el próximo día más o menos. Pero para que todo funcione, debe implementar algo como esto o usar un solucionador ODE estándar en Java. Siéntase libre de agregar comentarios o pedirme que vuelva a escribir esto o agregue más si es útil.
Ahora entiendo bastante bien lo que dices (aprendiendo Python como un efecto secundario :)). Probaré con RK4 después del 25 de septiembre, ya que no usaré mi computadora portátil durante los próximos 10 días.
@vishu OK, ¡eso es realmente genial! Ejecutar python de la manera que muestro aquí es muy, muy lento, normalmente no lo harías de esta manera, pero es una forma fácil de "prototipar". Si usa una biblioteca de integración como scipy.odeinto 'scipy.ode', es mejor.
Estaba tomando la aceleración promedio con el paso anterior, en cambio, con el próximo paso futuro habría sido similar a Euler modificado. Con el pequeño incremento de tiempo (2 s y 250 ms) debería haber compensado en parte la inexactitud, pero parece no ser suficiente para las órbitas con mayor curvatura de las lunas, lo cual entendí a partir de sus explicaciones. Gracias por eso. Probaré con RK4 después del 25 de septiembre.
@vishu Tómate tu tiempo; con un poco de suerte, el sistema solar seguirá existiendo entonces :-)
@vishu, así que lo pensé y decidí que mi respuesta existente realmente responde a la pregunta que ha hecho. He explicado cómo calcular "los planetas y las lunas según la fuerza gravitatoria de Newton". Su pregunta no cubre la adición de términos de relatividad general y gravedad de orden superior más allá del monopolo. Escribí esto como una nueva respuesta a una nueva pregunta y lo vinculé aquí. Si está de acuerdo en que esta respuesta (aquí) responde a esta pregunta, puede considerar aceptarla.
@vishu, pero si tiene preguntas sobre GR u otros términos, creo que ya es hora de que haga una nueva pregunta. También deberíamos hacer algunas tareas domésticas y recopilar la información que se encuentra en todos estos comentarios en la pregunta y la respuesta, y luego limpiar los comentarios. Los moderadores han sido amables al permitirnos trabajar así, pero deberíamos arreglar un poco.