Two_body_problem: scipy.integrate.RK45 выдает ошибку трансляции, и scipy.integrate.LSODA никогда не входит в функцию twoBody

1

Я работаю над калькулятором траектории для проблемы с двумя телами, и я пытаюсь использовать Scipy RK45 или LSODA для решения ODE и возврата траектории. (Пожалуйста, предложите другой метод, если вы считаете, что это лучший/более простой способ сделать это)

Я использую IDE Spyder с Anaconda. Scipy версия 1.1.0

ПРОБЛЕМЫ:

RK45: При использовании RK45 первый шаг, похоже, работает. При переходе через код в отладчике вводится значение twoBody() и работает точно так, как ожидалось, первый прогон. Однако, после первого return ydot, все начинает идти не так. С точкой останова на линии ydot[0] = y[3] мы начинаем видеть проблему. Массив y (который я ожидал быть 6x1) теперь представляет собой массив 6x6. При попытке оценить эту строку numpy возвращает ошибку ValueError: could not broadcast input array from shape (6) into shape (1). Есть ли ошибка в моем коде, которая заставит y перейти от 6x1 до 6x6? Ниже представлен массив y перед ошибкой вещания.

y = 
 -5.61494e+06   -2.01406e+06    2.47104e+06     -683.979    571.469  1236.76
-5.61492e+06    -2.01404e+06    2.47106e+06     -663.568    591.88   1257.17
-5.6149e+06     -2.01403e+06    2.47107e+06     -652.751    602.697  1267.99
-5.61492e+06    -2.01405e+06    2.47105e+06     -672.901    582.547  1247.84
-5.61492e+06    -2.01405e+06    2.47105e+06     -672.988    582.46   1247.75
-5.61492e+06    -2.01405e+06    2.47105e+06     -673.096    582.352  1247.64

Может ли мое начальное условие Y0 заставлять его достигнуть слишком малого шага и, следовательно, выйти из строя?

LSODA: Я также пытался использовать решатель LSODA. Однако он никогда не входит в twoBody() ! Точка прерывания внутри вершины twoBody() никогда не достигается, и программа возвращает время выполнения. Я понятия не имею, что здесь происходит. Угадав, я настроил его неправильно.

EDIT: То же самое происходит при использовании Scipy solve_ivp. Все другие методы интеграции возвращают широковещательную ошибку.

import numpy as np
import scipy.integrate as ode
from time import time
startTime = time()

def twoBody(t, y):
    """
    Two Body function returns the derivative of the state space variables.
INPUTS: 
    --- t ---
        A scalar time value. 

    --- y ---
        A 6x1 array of the state space of a particle in 3D space  
OUTPUTS:
    --- ydot ---
        The derivative of y for the two-body problem

"""
    mu = 3.986004418 * 10**14

    r = np.sqrt(y[0]**2 + y[1]**2 + y[2]**2)

    ydot    = np.empty((6,1))
    ydot[:] = np.nan

    ydot[0] = y[3]             
    ydot[1] = y[4]             
    ydot[2] = y[5]             
    ydot[3] = (-mu/(r**3))*y[0]
    ydot[4] = (-mu/(r**3))*y[1]
    ydot[5] = (-mu/(r**3))*y[2]

    return ydot


# In m and m/s
# first three are the (x, y, z) position
# second three are the velocities in those same directions respectively
Y0 = np.array([-5614924.5443320004,
               -2014046.755686,
               2471050.0114869997,
               -673.03650300000004,
               582.41158099999996,
               1247.7034980000001])

solution = ode.LSODA(twoBody, t0 = 0.0, y0 = Y0, t_bound = 351.0)
#solution = ode.RK45(twoBody, t0 = 0.0, y0 = Y0, t_bound = 351.0)

runTime = round(time() - startTime,6)
print('Program runtime was {} s'.format(runTime))
  • 0
    Я возьму это и посмотрю, что произойдет
  • 0
    Заменив его на np.zeros ((6,1)), ничего не меняется
Теги:
python-3.x
scipy
ode
runge-kutta

2 ответа

0
Лучший ответ

Вы также можете использовать scipy.integrate.odeint для такого рода задач, которые могут быть проще настроить:

import numpy as np
from scipy.integrate import odeint


def twoBody(y, t, mu):
    """
    Two Body function returns the derivative of the state space variables.
INPUTS:
    --- t ---
        A scalar time value.

    --- y ---
        A 6x1 array of the state space of a particle in 3D space
OUTPUTS:
    --- ydot ---
        The derivative of y for the two-body problem

"""

    r = np.sqrt(y[0]**2 + y[1]**2 + y[2]**2)

    ydot = np.empty((6,))

    ydot[0] = y[3]
    ydot[1] = y[4]
    ydot[2] = y[5]
    ydot[3] = (-mu/(r**3))*y[0]
    ydot[4] = (-mu/(r**3))*y[1]
    ydot[5] = (-mu/(r**3))*y[2]

    return ydot


# In m and m/s
# first three are the (x, y, z) position
# second three are the velocities in those same directions respectively
Y0 = np.array([-5614924.5443320004,
               -2014046.755686,
               2471050.0114869997,
               -673.03650300000004,
               582.41158099999996,
               1247.7034980000001])

mu = 3.986004418 * 10**14

solution = odeint(twoBody, Y0, np.linspace(0., 351., 100), args=(mu, ))

Я не могу судить о правильности вывода, но, похоже, он хорошо интегрируется.

0

Проблема в том, что вы определяете ydot как матрицу, то есть 2-мерный массив, даже если второе измерение имеет ширину только 1. Начальное значение представляет собой простой массив длины 6. При автоматическом преобразовании после модели идиосинкразий Matlab y0 интерпретируется как вектор строки, а массив (6,1), как обычно, как вектор столбца, сумма обоих равна ( 6,6) матрица.

a = np.zeros((3,1))
b = np.array([1,2,3.0])
a+b

array([[1., 2., 3.],
       [1., 2., 3.],
       [1., 2., 3.]])

Таким образом, на следующем шаге вы пытаетесь заполнить записи вектора ydot столбца (6,1) строками матрицы y (6,6), что дает сообщаемую ошибку.

Таким образом, избегайте смешивания разных типов векторов. определяющий

ydot = np.empty((6,))

делает это с минимальным изменением.


PS: Это может не иметь значения, но я бы взял время начала после интерпретации функции ODE, непосредственно перед вызовом решателя.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню