Значения для моделирования хаотического рассеяния не соответствуют базовому случаю

Мой первый пост о переполнении стека, будьте осторожны. Я написал код, чтобы отслеживать положение частицы массы M на плоскости x, y на потенциале V (r), описываемом четырехмерной системой уравнений движения.

M(dv/dt)=-grad V(r),      dr/dt=v,

Которые решаются с помощью метода 4-го порядка Рунге-Кутты, где r = (x, y) и v = (vx, vy); теперь состояние частицы определяется x, y и углом theta между вектором v и положительной осью x, где величина скорости определяется выражением

|v|=sqrt(2(E-V(r))/M)

где E - энергия в плоскости, а потенциал V (r) определяется выражением

V(r)=x^2y^2exp[-(x^2+y^2)],

вот код, который я сделал для начальных значений

x(0)=3,
y(0)=0.3905,
vx(0)=0,
vy(0)=-sqrt(2*(E-V(x(0), y(0)))),

где E = 0,260 * (1 / exp (2))

    // RK4
    #include <iostream> 
    #include <cmath> 

    // constant global variables
    const double M = 1.0;
    const double DeltaT = 1.0;

    // function declaration
    double f0(double t, double y0, double y1, double y2, double y3); // derivative of y0
    double f1(double t, double y0, double y1, double y2, double y3); // derivative of y1
    double f2(double t, double y0, double y1, double y2, double y3); // derivative of y2
    double f3(double t, double y0, double y1, double y2, double y3); // derivative of y3
    void rk4(double t, double h, double &y0, double  &y1, double &y2, double &y3); // method of runge kutta 4th order
    double f(double y0, double y1); //function to use

    int main(void) 
    {
      double y0, y1, y2, y3, time, E, Em;
      Em = (1.0/(exp(2.0)));
      E = 0.260*Em;
      y0 = 3.0; //x
      y1 = 0.3905; //y
      y2 = 0.0; //vx
      y3 = -(std::sqrt((2.0*(E-f(3.0, 0.0)))/M)); //vy
      for(time = 0.0; time <= 400.0; time += DeltaT) 
        {
          std::cout << time << "\t\t" << y0 << "\t\t" << y1 << "\t\t" << y2 << "\t\t" << y3 << std::endl;
          rk4(time, DeltaT, y0, y1, y2, y3);
        }


      return 0;
    }

    double f(double y0, double y1)
    {
      return y0*y0*y1*y1*(exp(-(y0*y0)-(y1*y1)));
    }

    double f0(double t, double y0, double y1, double y2, double y3)
    {
      return y2;
    }

    double f1(double t, double y0, double y1, double y2, double y3)
    {
      return y3;
    }


    double f2(double t, double y0, double y1, double y2, double y3)
    {
      return 2*y0*((y0*y0)-1)*(y1*y1)*(exp(-(y0*y0)-(y1*y1)))/M;
    }

    double f3(double t, double y0, double y1, double y2, double y3)
    {
      return 2*(y0*y0)*y1*((y1*y1)-1)*(exp(-(y0*y0)-(y1*y1)))/M;
    }


    void rk4(double t, double h, double &y0, double &y1, double &y2, double &y3) // method of runge kutta 4th order
    {
      double k10, k11, k12, k13, k20, k21, k22, k23, k30, k31, k32, k33, k40, k41, k42, k43;
      k10 = h*f0(t, y0, y1, y2, y3);
      k11 = h*f1(t, y0, y1, y2, y3);
      k12 = h*f2(t, y0, y1, y2, y3);
      k13 = h*f3(t, y0, y1, y2, y3);
      k20 = h*f0(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
      k21 = h*f1(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
      k22 = h*f2(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
      k23 = h*f3(t+h/2, y0 + k10/2, y1 + k11/2, y2 + k12/2, y3 + k13/2);
      k30 = h*f0(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
      k31 = h*f1(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
      k32 = h*f2(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
      k33 = h*f3(t+h/2, y0 + k20/2, y1 + k21/2, y2 + k22/2, y3 + k23/2);
      k40 = h*f0(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
      k41 = h*f1(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
      k42 = h*f2(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);
      k43 = h*f3(t + h, y0 + k30, y1 + k31, y2 + k32, y3 + k33);


      y0 = y0 + (1.0/6.0)*(k10 + 2*k20 + 2*k30 + k40);
      y1 = y1 + (1.0/6.0)*(k11 + 2*k21 + 2*k31 + k41);
      y2 = y2 + (1.0/6.0)*(k12 + 2*k22 + 2*k32 + k42);
      y3 = y3 + (1.0/6.0)*(k13 + 2*k23 + 2*k33 + k43);

    }

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

как должен выглядеть рисунок с заданными начальными условиями как должен выглядеть рисунок с  заданы начальные условия

Теперь я думаю, что правильно понял реализацию метода, но я не знаю, почему графики не совпадают, потому что, когда я запускаю код, частица уходит от потенциала.

Любая помощь будет оценена по достоинству.


person spenam    schedule 21.11.2016    source источник
comment
См. Также ответ stackoverflow.com/a/30582741/3088138 для решения ODE с boost/numeric/odeint   -  person Lutz Lehmann    schedule 21.11.2016


Ответы (1)


Дорожки выглядят хаотично с крутыми поворотами. Для этого требуется адаптивный размер шага, вам нужно будет реализовать некоторый контроль размера шага. Либо сравнивая каждый шаг с двумя шагами половинной длины шага, либо используя метод со встроенными методами более высокого порядка, такими как Фельберг или Дорман-Прайс.


Более непосредственные ошибки:

  • определите Em как V(1,1), чтобы избежать ненужных магических чисел
  • ваша начальная позиция, если вы правильно прочитали диаграмму,

    y0 = 3.0;
    y1 = -0.3905+k*0.0010; 
    

    с k=-1,0,1 обратите внимание на знак минус.

  • ваша начальная скорость горизонтальна, и кинетическая энергия вычисляется, чтобы дополнить потенциальную энергию в этом положении. Таким образом

    y2 = v0 = -(std::sqrt((2.0*(E-V(y0, y1)))/M));
    y3 = v1 = 0.0;
    

С этими изменениями и адаптивным решателем я получаю (в python) график

воспроизведение сюжета из процитированной статьи

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

# capture the structure of the potential
f  = lambda     r :     r*np.exp(-r);
df = lambda     r : (1-r)*np.exp(-r);
V  = lambda y1,y2 : f(y1*y1)*f(y2*y2);

M= 1.0
Em = V(1.0,1.0);
E = 0.260*Em;

def prime(t,y):
    x1,x2,v1,v2 = y        
    dV_dx1 = 2*x1*df(x1*x1)*f(x2*x2);
    dV_dx2 = 2*x2*df(x2*x2)*f(x1*x1);
    return [ v1, v2, -dV_dx1/M, -dV_dx2/M ];

# prepare and draw the contour plot
X1,X0=np.ogrid[-4:3:100j,-4:3:100j]
plt.contour(X0.ravel(), X1.ravel(), V(X0,X1), Em*np.arange(0,1,0.1), colors='k', linewidths=0.3)
# display grid and fix the coordinate ranges
plt.grid();plt.autoscale(False)

for k in range(-1,1+1):

    x01 = 3.0; 
    x02 = b = -0.3905 + 0.0010*k; 
    v01 = -( ( E-V(x01,x02) )*2.0/M )**0.5; 
    v02 = 0.0; 
    print "initial position (%.4f, %.4f), initial velocity (%.4f, %.4f)" % ( x01, x02, v01, v02 )

    t0 = 0.0
    tf = 50.0
    tol = 1e-10
    y0 = [ x01, x02, v01, v02 ]
    t = np.linspace(t0,tf,501); y = odeint(lambda y,t: prime(t,y) , y0, t)

    plt.plot(y[:,0], y[:,1], label="b=%.4f" % b, linewidth=2)

plt.legend(loc='best')
plt.show()
person Lutz Lehmann    schedule 21.11.2016
comment
Отлично, но в моем коде, когда я применяю ваши исправления, он все равно не рисует правильные пути, частица уходит на противоположную сторону и не взаимодействует с потенциалом. Я думаю, что ошибка заключается в реализации метода рунге-кутта, но я не знаю, в чем ошибка. - person spenam; 22.11.2016
comment
@spenam: Ты заставлял vy=0 и vx переносить кинетическую энергию? Из моего адаптивного размера шага для RK4 я вижу, что при тесном взаимодействии с потенциалами размер шага должен быть не меньше 0.02. Ваш размер шага 1 слишком велик. - Сообщите свой вектор начальных значений после того, как все в нем вычислено. - person Lutz Lehmann; 22.11.2016
comment
@spenam: Я модифицировал программу C ++ во всех этих пунктах, и даже с размером шага 1 путь визуально правильный. В коде RK4 нет ошибок, даже если он не очень объектно ориентирован. - person Lutz Lehmann; 22.11.2016
comment
Да, когда я делаю vy = 0 и vx, несущими кинетическую энергию, частица следует по пути примера, я думаю, книга была неправильной, когда они написали начальные условия графика, большое спасибо, чувак! - person spenam; 22.11.2016
comment
Привет, не могли бы вы дать мне полный код, который вы сделали для графика? Я не могу получить хороший график на C ++ и ничего не знаю о python. - person spenam; 28.11.2016
comment
Выполнено. Большая часть графического материала ясна в ретроспективе, но хорошо, что поисковые системы находят множество примеров в учебных пособиях и отвечают на вопросы. - person Lutz Lehmann; 28.11.2016