Значения по умолчанию в solve_ivp
сделаны для «нормальной» ситуации, когда шкалы переменных не слишком отличаются от диапазона от 0,1 до 100. Вы можете достичь этих шкал, изменив масштаб задачи так, чтобы все длины и связанные константы находятся в AU, а все время и связанные константы - в днях.
Или вы можете попытаться установить абсолютное допуск на что-то разумное, например 1e-4*AU
.
. Это также помогает использовать правильная система первого заказа, как я недавно говорил вам в другом вопросе по этой теме c. В механической системе вы обычно получаете ODE второго порядка x''=a(x)
. Тогда система первого порядка, которая будет передана в решатель ODE, - это [x', v'] = [v, a(x)]
, которая может быть реализована как
def firstorder(t,state):
pos, vel = state.reshape(2,-1);
return [*vel, *accelerations2(t,pos)]
Далее всегда полезно применить ускорение Земли к Земле и Солнца к Солнцу. , То есть, исправить порядок объектов. В данный момент инициализация имеет сначала Солнце, а в расчете ускорения вы сначала рассматриваете состояние как Землю. Сначала переключите все на солнце
def accelerations2(t,pos):
pos=pos.reshape(-1,3)
# pos[0] = sun, pos[1] = earth
norme=sum( (pos[1]-pos[0])**2 )**0.5
gravit = G*(pos[1]-pos[0])/norme**3
sunacc = me*gravit
earthacc = -ms*gravit
totacc=earthacc+sunacc
return [*sunacc,*earthacc]
И тогда никогда не сработает использование правильно воспроизведенных натуральных констант, таких как
G = 6.67E-11
Затем вызов решателя и форматирование печати как
state0=[*sunpos, *earthpos, *sunvel, *earthvel]
sol = solve_ivp(firstorder, [0, T], state0, first_step=1e+5, atol=1e-6*a)
print(sol.message)
for t, pos in zip(sol.t, sol.y[[0,1,3,4]].T):
print("%.6e"%t, ", ".join("%8.4g"%x for x in pos))
дает короткую таблицу
The solver successfully reached the end of the integration interval.
t x_sun y_sun x_earth y_earth
0.000000e+00 -9.035e+05, -6.896e+06, 7.5e+10, 0
1.000000e+05 -9.031e+05, -6.896e+06, 7.488e+10, 5.163e+09
, то есть для этого шага решателю требуется только один внутренний шаг.