1

I'm trying to create a GUI in Python using Tkinter that plots the orbital path of a mass using the Runge-Kutta method. My GUI works fine but my issue is that it only plots a straight line no matter what values I input to the GUI. I was hoping someone could show me what is wrong with my function within the GUI so that it will actually plot the orbit properly.

def calcPath(self):
    M = float(self.entM.get())
    m = float(self.entm.get())
    G = 6.67e-11
    c = 3e8



    velocity = np.array([float(self.entvx.get()),float(self.entvy.get()),float(self.entvz.get())])
    pos = np.array([float(self.entx.get()), float(self.enty.get()), float(self.entz.get())])

    Force = lambda pos: (G*m*M/(pos**2))

    #assigning variables empty lists to append x, y and z values to
    a = [] 
    b = []
    c = []
    t = 0.0
    tf = float(self.enttf.get())
    dt = float(self.entdt.get())

    while t < tf: # creating a while loop to trace the path for a set period of time
        #using the Runge-kutta formula from the problem sheet to assign variables at different steps and half steps 
        k1v=(dt*Force(pos))/m
        k2v=(dt*Force(pos+(k1v/2.0)))/m 
        k3v=(dt*Force(pos+(k2v/2.0)))/m 
        k4v=(dt*Force(pos+k3v))/m
        velocity=velocity+(k1v/6.0)+(k2v/3.0)+(k3v/3.0)+(k4v/6.0) #calaculating the weighted average of the k values
        pos=pos+velocity*dt #velocity is not a function of space or time so it will be identical at all 4 k values

        a.append(pos[0]) # appending the lists for each vaiable to produce a plot
        b.append(pos[1])
        c.append(pos[2])
        t = t+dt # setting the time steps

    #generating the path plot figure and formatting it    
    ax = Axes3D(self.fig) #creating a 3D figure 
    ax.set_title("Path of planetary mass") #produces title on the figure
    ax.plot3D(a,b,c, color='darkviolet', label='Runge-kutta path method') 
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    ax.legend(loc='lower left') #selecting the location of legend
    self.canvas.show()
S.H
  • 41
  • 5
  • not sure, but would it be possible that `pos[0]` (and others) use the same reference for all iterations, resulting in the same values in `a`, `b` and `c` ? – Jean-François Fabre Dec 01 '16 at 20:52
  • I've changed the force function to use np.square on the position array but unfortunately It still just plots a straight line when I run it – S.H Dec 01 '16 at 21:40
  • can you `print(id(pos[0])` at each iteration and see if it yields the same number? – Jean-François Fabre Dec 01 '16 at 21:41

1 Answers1

1

Your physics is wrong. And your treatment of the motion equation is wrong.

The force computes as

Force = lambda pos: -G*m*M/(norm2(pos)**3)*pos

and the motion equation is

m·pos''(t) = Force(pos(t))

where

pos''(t) = d²/dt² pos(t)

which you have to transform into a first order system

[ pos' , vel' ] = [ vel, Force(pos)/m ]

To this first order system you can now apply the RK4 method.

    k1p = dt *       vel
    k1v = dt * Force(pos        ) / m
    k2p = dt *      (vel+0.5*k1v) 
    k2v = dt * Force(pos+0.5*k1p) / m 
    k3p = dt *      (vel+0.5*k2v) 
    k3v = dt * Force(pos+0.5*k2p) / m 
    k4p = dt *      (vel+    k3v)
    k4v = dt * Force(pos+    k3p) / m
    pos = pos + (k1p+2*k2p+2*k3p+k4p)/6.0 
    vel = vel + (k1v+2*k2v+2*k3v+k4v)/6.0 

Note how the k vectors interleave between position and velocity.


Or you can make the correct RK4 implementation automatic using

System = lambda pos, vel : vel, Force(pos)/m

and then inside the time loop

    k1p, k1v = System( pos           , vel           )
    k2p, k2v = System( pos+0.5*k1p*dt, vel+0.5*k1v*dt )
    k3p, k3v = System( pos+0.5*k2p*dt, vel+0.5*k2v*dt )
    k3p, k3v = System( pos+    k3p*dt, vel+    k3v*dt )
    pos = pos + (k1p+2*k2p+2*k3p+k4p)*dt/6.0 
    vel = vel + (k1v+2*k2v+2*k3v+k4v)*dt/6.0 

And if you just want the numerical solutions, i.e., do not have to prove that you can implement RK4, then use scipy.integrate.ode or scipy.integrate.odeint.

Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51
  • What modules have you imported? It comes up with invalid syntax with the m*pos'' = Force(pos) – S.H Dec 02 '16 at 11:49
  • That is not python, but the ASCII rendering of a differential equation. `m·d²/dt² pos(t) = m·pos''(t) = F(pos(t))`. – Lutz Lehmann Dec 02 '16 at 11:56
  • And `norm2` is `numpy.linalg.norm`. One can replace `norm2(pos)**3` with `np.dot(pos,pos)**1.5`. This avoids the norm type selection logic in `numpy.linalg.norm`. – Lutz Lehmann Dec 02 '16 at 12:03
  • I've corrected the k1p and k1v ect. formulas, however I don't see how the new vel is meant to feed into the plot – S.H Dec 02 '16 at 17:16
  • As you are not plotting the velocity, you do not need `vel` resp. `velocity` in the plot. Its influence on the position is exerted during the state updates in the RK4 steps. – Lutz Lehmann Dec 02 '16 at 17:35