Расчет планет и лун на основе гравитационной силы Ньютона

Я пытаюсь понять, как рассчитать орбиты тел Солнечной системы в рамках n тел, основываясь на парном гравитационном взаимодействии между объектами. В настоящее время я рассматриваю 44 объекта (солнце, планеты, большие луны и большие астероиды).

Я начинаю с векторов состояния (положения и скорости) каждого из объектов с Солнцем в центре, полученных из telnet ssd.jpl.nasa.gov 6775(JPL Horizons) 01 января 2017 года в 00:00 UTC, и хотел бы, чтобы система развивалась в течение 43:44, 01- Июль-2017 в 00:00ч.

Я написал программу для этого на Java, и до сих пор результаты не кажутся даже достаточно близкими к тому, чем они должны быть, по сравнению с векторами состояния, полученными из Horizons. После каждых 2-секундных временных шагов рассчитываются суммарные гравитационные силы, воздействующие на каждое тело от всех остальных, а затем за один раз обновляются все скорости и положения на основе ускорений от этих суммарных сил. Затем я сравниваю окончательные обновленные векторы положения из приложения с данными, полученными от Horizons после поправки на обновленное положение Солнца.

Сравнение показывает, что положение Земли и внешних планет имеет ошибку положения менее 50 км (на самом деле, чем дальше планеты, тем меньше 10 км). Где у Меркурия погрешность 250км. А спутники Юпитера и Сатурна разнесены на 50 000–300 000 км!

В своем приложении я не делаю различий между Солнцем, планетами и лунами, поэтому я не уверен, почему для лун должно быть так много ошибок. Я попытался уменьшить размер шага с 2 секунд до 0,25 секунды, но существенного улучшения не произошло.

Какие могут быть проблемы, которые я должен исследовать здесь? Есть ли вещи, которые явно нуждаются в улучшении прямо сейчас? Или, возможно, есть тесты, которые я могу сделать, чтобы помочь диагностировать основные источники ошибок?


РЕДАКТИРОВАТЬ: Вот суть метода расчета, как запрошено в комментариях:

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

allItemLinksэто коллекции ItemLink- связи между объектами. в этом случае гравитационная связь между всеми парами объектов. Для nобъектов будут n.(n+1)/2ссылки

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)
}

В 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
}

allItemsпредставляет собой набор объектов Item (Солнце, планеты и луны)

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

В элементе:

netForce, nowAcc, effectiveAcc, deltaV, newPos etc.все 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
}

Работает не с гравитационными полями, а с прямыми силами за счет межобъектной гравитации.

С помощью приведенного выше кода я могу получить стабильные орбиты. Даже время обращения лун хорошо. Получите красивый набор Сатурна с циклоидальным движением лун и набор Урана с спиральным движением лун вокруг Урана. Я не знаю, как отправить файлы или изображения для этого обсуждения

Смещение Меркурия было бы правильным из-за релятивистских эффектов. Я бы обвинил в неточности положения лун ошибки численной точности, особенно то, что они сильно взаимодействуют друг с другом.
Кроме того, если вы рассчитаете их положение относительно Солнца йо Для Ио, вы получите большую полуось с радиусом орбиты 0,003 а.е. на расстоянии 5,2 а.е. от Солнца. Это плохо работает со значениями с плавающей запятой, так как фиксированное большое смещение от центра системы координат не позволяет им повысить точность за счет изменения мантиссы, и изменения происходят в дальнем хвосте основания с большой потерей точности за его хвостом.
Это больше проблема КС. Какую точность вы используете? Рассматривали ли вы интеграторы Рунге-Кутты и/или симплектические интеграторы? То, что у вас здесь, - это проблема n-тела. Ошибка для ртути, вероятно, связана с релятивистскими эффектами.
Я не думаю, что Меркурий, отклонившийся на 250 км за семь дней, имеет какое-то отношение к теории относительности или спутникам Юпитера на 100 000 км. Луны имеют наихудшую ошибку, потому что у них самый короткий период и, следовательно, больше всего изменений. Я предполагаю, что вы просто используете в я + 1 знак равно в я + Δ т   Ф / м ; Икс я + 1 знак равно Икс я + Δ т   в я и ничего больше, но мы не узнаем, пока вы не поделитесь больше. Если вы хотите написать его самостоятельно и не хотите использовать библиотечный решатель, RK4 или RK4(5) составляют всего около двух десятков строк или около того.
Продолжительность расчета 6 месяцев (с 01 января 2017 г. по 01 июля 2017 г.).
Я кодирую на Java с помощью Vector3d («двойные» переменные). Подозревая проблему с точностью, попробовал использовать Big Decimal (32 значащих цифры) для позиций Европы и Юпитера (только один объект с BigDecimal, поскольку вычисление занимает слишком много времени). Тем не менее, ошибка для Европы была очень большой, как и в более ранних расчетах с «двойным». Я не использую никаких методов интегрирования - просто численные добавления, обновление позиций и скорости каждые 2 секунды.
Какие числа вы используете для массы (или параметров массы)? Вы также можете прочитать astronomy.stackexchange.com/questions/2416/…
Если вы не используете хотя бы простой интегратор RK4, то всегда будете получать совершенно неверные ответы. Это не точность, это не относительность, вы просто используете метод Эйлера , который , будучи только 1-го порядка , сам по себе не даст вам ничего близкого к физически правильной орбите. Просто взгляните на первое изображение в статье Википедии i.stack.imgur.com/hfAv5.png Пока вы не разместите некоторые уравнения или строки кода в теле вашего вопроса , я не могу опубликовать полный ответ, но 1-й заказ здесь бесполезен.
Или вы можете просто посмотреть , как решать ОДУ с помощью Java? . Это показывает использование алгоритма Dopri853 (более высокий порядок, интерполяция, адаптивный размер шага RK) из решателя Apache Commons ODE для планет в java. Обратите внимание и на ответ!
@uhoh Спасибо, что переместили мои дополнительные данные в основной вопрос.
@uhoh извините, есть недоразумение. Я имел в виду, что у меня есть орбиты, поскольку вы упомянули, что орбиты могут не закрыться. Честно говоря, я был в восторге, когда увидел циклоидальные и винтовые движения, и я слишком выразился. Похоже, что базовый подход может быть правильным для планет, но имеет проблемы при работе с лунами и при проверке того, требуется ли какое-либо особое обращение с массивными объектами. Я ценю ваш очень активный полезный ответ. Мне нужна помощь для этого.
Без проблем! Я начал удалять старые комментарии. Я думаю, что это действительно хороший вопрос! Я постараюсь опубликовать ответ через день или два, и, возможно, другие тоже. Вам нужно использовать интеграцию более высокого порядка, чем метод Эйлера 1-го порядка, который вы описываете, я постараюсь дать вам как минимум два варианта.
@СФ. похоже ты прав! Включение общей теории относительности необходимо, чтобы зафиксировать Меркурий. Во время каждого витка происходит циклический выбег в несколько сотен км. Я неправильно понял время интеграции (думал, что это семь дней), но в течение нескольких месяцев это необходимо. Опубликую результаты GR, как только смогу построить красивый график и ввести математику в MathJax.
@ооо я вернулся. Я изменил свой код для RK4. т.е. для каждого объекта перепозиционируется методом RK4. Во время метода RK4 для конкретного объекта все остальные объекты сохраняются в местах предыдущего шага. Сравнивая результаты (через 6 месяцев с 20170101) с Horizons, я обнаружил, что ошибка очень высока с шагом 100 с, меньше с шагом 10 с. Даже с шагом в 2 с ошибки составляют Землю 30 км, Юпитер 17 км, Внешние растения менее 3 км. Но Венера 50, Меркурий 240, Европа 120000, Ио 330000 и т.д. Любые комментарии. Это с релятивистским эффектом или гравитационным эффектом с временной задержкой на скорости света?
@vishu правильный способ распространения нескольких тел - построить один единственный вектор со всеми переменными положения и скорости . Итак (как я уже упоминал в своем ответе), если бы было два тела, вы бы использовали у знак равно ( Икс 1 , у 1 , г 1 , Икс 2 , у 2 , г 2 , в Икс 1 , в у 1 , в г 1 , в Икс 2 , в у 2 , в г 2 ) который находится Xв моем скрипте Python, для н тел вектор будет иметь длину 6 н . Все переменные продвигаются параллельно на каждом из четырех подшагов каждой итерации интеграции RK. Также я бы воздержался от спутников Юпитера, пока вы не добавите гравитационные кратные более высокого порядка (например, Дж 2 ) из-за сплющенности.
Я не понял «гравитационные кратные более высокого порядка (например, J2)».
@uhoh снова со всеми переменными, продвинутыми параллельно для каждого подэтапа RK4. Теперь я нахожу постоянную ошибку относительно Horizon через 6 месяцев с 20170101 00:0. Я имею в виду, что ошибка для планет и больших лун все еще существует, но почти остается неизменной с шагом расчета 10, 100, 600 или даже 1800 с. Но с 1800-х Фобос-Марс начинает убегать от Марса. Кажется, что 1800-е годы слишком большой шаг для Фобоса с очень коротким периодом обращения. Мой вывод, RK4 позволил увеличить время шага (скажем, 600 с), но все еще остаются ошибки по некоторым причинам, отличным от шага расчета.
@vishu хорошо, это отличные новости! Убедитесь, что вы используете наилучшие значения стандартных гравитационных параметров ( грамм раз М ), последние номера JPL можно найти в этом вопросе . После этого есть две большие поправки к простой ньютоновской гравитации между точками и массами, которые я могу придумать; 1. Общая теория относительности (ОТО) и 2. гравитационные мультиполи более высокого порядка (например , Дж 2 и далее) и приливные силы. Меркурий покажет большое улучшение с ОТО, а Земля-Луна и спутники планет-гигантов покажут улучшение с неточечной гравитацией.
@vishu проверь свои массы, и я обновлю/добавлю ответ для части GR и что-нибудь для решения Дж 2 . Дайте мне день или около того.
Все значения GM взяты из sd.jpl.nasa.gov/pub/xfr/gm_Horizons.pck. Спасибо. Я подожду, не торопись.
Ошибка с моей стороны, это ftp на 'ssd.jpl.nasa.gov/pub/xfr/gm_Horizons.pck'

Ответы (2)

Помимо числовых проблем, «С Солнцем в центре» может быть частью вашей проблемы. Получите все данные от Horizons относительно барицентра Солнечной системы, а не Солнца, которое движется относительно барицентра. Этот барицентр является инерциальной системой отсчета, а центр Солнца — нет. Также убедитесь, что вы вводите начальное положение и скорость Солнца и позволяете ему двигаться, если вы еще этого не сделали.

Хорошая точка зрения! Я этого даже не заметил.
Я беру данные с горизонтов с центром Солнца в 20170101 и позволяю объектам реагировать и двигаться. Первоначально положение и скорость Солнца равны 000. Во время расчета Солнце движется. После завершения расчетов до 20170701 года все полученные данные модифицируются обратно относительно нового положения и скорости Солнца как базы. Затем это снова сравнивается с данными Horizons за 20170701 год с помощью Sun-center.
Я рекомендую вам получить все данные относительно барицентра Солнечной системы (@0). Не Солнце (@10). Если вы сделаете это правильно, у Солнца не будет начального положения и скорости, равных нулю. Тогда вам не нужно перебазировать к новому положению Солнца и скорости в конце.
Но не в том ли дело, что сам Барицентр зависит от взаимного положения планеты. Я могу понять, что барицентр Земля-Луна фиксирован относительно Земли и Луны. Но с несколькими планетами разве это не меняется в зависимости от положения планет.
Нет. В этом весь смысл поиска и использования барицентра. Это центр масс всех тел Солнечной системы, поэтому в силу сохранения импульса он не движется в инерциальной системе отсчета замкнутой Солнечной системы, независимо от того, как движутся тела в Солнечной системе.
@mark Спасибо. Позвольте мне сначала разобраться с этим (сохранение импульса и, следовательно, центр не движется - конечно, учитывая изолированную солнечную систему). Я попробую с данными из барицентра Солнечной системы. Это (может быть) улучшит точность планет, но большая ошибка для меньших лун ... У меня, кажется, другая проблема. Вернусь
@mark Я провел расчеты с данными g@0 из Horizons и сравнил конечные результаты с данными g@0 на дату окончания. Значения ошибок точно такие же, как и раньше. Одним из основных преимуществ является то, что мне не нужно корректировать конечные позиции и скорости, чтобы центрировать их с новым положением солнца для сравнения результатов с данными g@10 на дату окончания. Из-за ошибки малых лун я играю со своим пониманием времени распространения гравитации и замедления времени :). Дайте-ка подумать ..
У вас, вероятно, проблемы с числами или параметрами лун. Движение лун следует интегрировать относительно тел, вокруг которых они вращаются, рассматривая другие тела как возмущения. По сравнению с их расстоянием от Солнца, луны перемещаются относительно своего родительского тела на очень небольшие расстояния. Также вам нужно иметь точные GM для всех тел. (Обычно такие данные можно найти в выходных заголовках Horizons.)
Все значения GM взяты из ssd.jpl.nasa.gov/pub/xfr/gm_Horizons.pck.
@MarkAdler Как имитировать движение Солнца? Ньютоновская гравитация других планет?

Я опубликую численные методы в этом ответе и полномасштабный расчет солнечной системы (включая теорию относительности и возможные эффекты сплюснутой формы Солнца) в качестве второго ответа. Слишком много, чтобы поместить все это в один ответ.

Метод, который вы описываете, выглядит как метод Эйлера или то, что можно назвать методом Эйлера вперед . На каждом временном шаге д т вы вычисляете все силы и их результирующие чистые ускорения а , а затем просто увеличивайте скорость в от а д т и все позиции Икс от в д т . Вам нужны абсурдно крошечные временные шаги, чтобы приблизиться к этому. Вы упомянули 2 секунды и 250 миллисекунд, что немного меньше для шкалы времени Солнечной системы.

В приведенном ниже сценарии я написал метод Эйлера вперед и еще два метода низкого порядка Рунге-Кутты , обычно называемые RK2 и RK4. Для каждого метода рассчитывается упрощенная (фиктивная) орбита Меркурия вокруг фиксированного Солнца за 100 дней с количеством итераций от 10 до 10 000. Кроме того, для каждого я использую решатель библиотеки SciPyodeint() с относительным допуском точности 1E-12 на шаг. odeint — это оболочка Python lsodaиз библиотеки FORTRAN odepack.

Вы можете видеть, что даже RK4 соглашается с odeint уровнем метров через 100 дней. , если вы используете временной шаг около 15 минут, а метод Эйлера вперед (то, что вы используете) потребует абсурдного количества шагов, чтобы хотя бы приблизиться к этому.

Численные методы - не единственная проблема здесь, я опубликую второй ответ через несколько дней с остальным, что вам нужно. Я могу сделать это под отдельным вопросом, а не публиковать два ответа на один и тот же вопрос .

Но это должно заставить вас начать либо кодировать RK4 в java, либо искать числовую библиотеку java, такую ​​​​как Apache, упомянутая в комментариях.

Самый простой стандартный способ решить орбитальную задачу с помощью решателя ОДУ — поместить все декартовы координаты и скорости в один длинный вектор, назовем его у , и напишите одну функцию для производной по времени:

у ˙ знак равно ф ( т , у )

Итак, если бы у вас было два тела и три измерения, вектор у было бы:

у знак равно ( Икс 1 , у 1 , г 1 , Икс 2 , у 2 , г 2 , в Икс 1 , в у 1 , в г 1 , в Икс 2 , в у 2 , в г 2 )

с шестью элементами на тело. производная от Икс 1 является в Икс 1 , и производная от в Икс 1 это ускорение а Икс 1 из-за всех остальных тел.

Скажем, у вас есть одно тело в центральной силе со стандартным гравитационным параметром грамм М . Скорость изменения положения - это просто скорость,

д Икс д т знак равно в

а скорость изменения скорости есть ускорение, вызванное силой;

д в д т знак равно а знак равно грамм М р р 3

Если у вас было несколько тел, р будет расстояние между парами тел, и для каждого тела вы суммируете все остальные, как вы уже описали.

Итак, если вы написали ф , это было бы:

ф знак равно ( в Икс , в у , в г , грамм М Икс / р 3 , грамм М у / р 3 , грамм М г / р 3 ) .

Метод Euler Forward, который, как я полагаю, вы используете, просто повторяет

у я + 1 знак равно час   ф ( т , у я )

с временными шагами час . Улучшенный метод RK2 (показан ниже) будет записан так:

к 1 знак равно ф ( т , у я )
к 2 знак равно ф ( т + час 2 , у я + час 2 к 1 )
у я + 1 знак равно у н + час к 2

а вездесущий метод RK4 записывается как

к 1 знак равно ф ( т , у я )
к 2 знак равно ф ( т + час 2 , у я + час 2 к 1 )
к 3 знак равно ф ( т + час 2 , у я + час 2 к 2 )
к 4 знак равно ф ( т + час , у я + к 3 )

у я + 1 знак равно у н + час ( к 1 + 2 к 2 + 2 к 3 + к 4 ) / 6

Вот раздел, который показывает сходство и различия между методом Эйлера Форвард (самый простой метод Рунге-Кутта) и двумя методами РК более высокого порядка. Это написано для ясности, а не скорости явно.

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

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 Я буду продолжать добавлять к этому, если что-то неясно, оставьте сообщение. Для меня хорошей практикой является записывать все это — иногда четкое объяснение может быть проблемой. Кто-то еще , пожалуйста, комментарии и предложения по улучшению ясности приветствуются!
@vishu это выглядит полезным? Добавление общей теории относительности к ф исправит проблему с Меркурием, и на самом деле это всего лишь еще несколько строк кода - я постараюсь добавить его как-нибудь на следующий день или около того. Но чтобы все заработало, вам нужно либо реализовать что-то подобное, либо использовать стандартный решатель ODE на Java. Пожалуйста, не стесняйтесь добавлять комментарии или просить меня переписать это или добавить больше, если это поможет.
Теперь я довольно хорошо понимаю, о чем вы говорите (изучение Python как побочный эффект :)). Я попробую с RK4 после 25 сентября, так как я не буду использовать свой ноутбук в течение следующих 10 дней.
@vishu Хорошо, это действительно здорово! Запуск python так, как я здесь показываю, очень медленный, вы обычно не делаете это таким образом, но это простой способ «прототипа». Если вы используете интеграционную библиотеку, такую ​​​​как scipy.odeintили «scipy.ode», это лучше.
Я брал среднее ускорение с предыдущим шагом, вместо этого следующий будущий шаг был бы похож на Модифицированный Эйлер. Небольшое время приращения (2 с и 250 мс) должно было частично компенсировать неточность, но похоже, что этого недостаточно для орбит с более высокой кривизной лун, что я понял из ваших объяснений. Спасибо за это. Я попробую с RK4 после 25 сентября.
@vishu Не торопитесь; если повезет, Солнечная система все еще будет существовать :-)
@vishu, поэтому я подумал об этом и решил, что мой существующий ответ действительно отвечает на вопрос, который вы задали. Я объяснил, как рассчитать «планеты и луны на основе гравитационной силы Ньютона». Добавление терминов общей теории относительности и гравитации более высокого порядка помимо монополя не распространяется на ваш вопрос. Я написал это как новый ответ на новый вопрос и связал его здесь. Если вы согласны с тем, что этот ответ (здесь) отвечает на этот вопрос, вы можете принять его.
@vishu, но если у вас есть вопросы о GR или других терминах, я думаю, самое время задать новый вопрос. Мы также должны сделать некоторую домашнюю работу и собрать информацию, содержащуюся во всех этих комментариях, в вопрос и ответ, а затем очистить комментарии. Модераторы любезно позволили нам работать в таком режиме, но нам следует немного привести себя в порядок.