Satellite position computation using Runge-Kutta 4 - python
my issue is related to Runge-Kutta 4 (RK4) method and the correct iteration steps required for the state vector of an orbiting satellite.
The below code (in Python) describes the motion based on the description as per this link (http://www.navipedia.net/index.php/GLONASS_Satellite_Coordinates_Computation):
if total_step_number != 0:
for i in range(1, total_step_number+1):
#Calculate k1
k1[0] = (-cs.GM_GLONASS * XYZ[0] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ[0] * (1 - (5*(XYZ[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[0] + (cs.OMEGAE_DOT**2 * XYZ[0]) + (2 * cs.OMEGAE_DOT * XYZDot[1])
k1[1] = (-cs.GM_GLONASS * XYZ[1] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ[1] * (1 - (5*(XYZ[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[1] + (cs.OMEGAE_DOT**2 * XYZ[1]) - (2 * cs.OMEGAE_DOT * XYZDot[0])
k1[2] = (-cs.GM_GLONASS * XYZ[2] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ[2] * (3 - (5*(XYZ[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[2]
#Intermediate step to bridge k1 to k2
XYZ2[0] = XYZ[0] + (XYZDot[0] * h / 2) + (k1[0] * h**2 / 8)
XYZDot2[0] = XYZDot[0] + (k1[0] * h / 2)
XYZ2[1] = XYZ[1] + (XYZDot[1] * h / 2) + (k1[1] * h**2 / 8)
XYZDot2[1] = XYZDot[1] + (k1[1] * h / 2)
XYZ2[2] = XYZ[2] + (XYZDot[2] * h / 2) + (k1[2] * h**2 / 8)
XYZDot2[2] = XYZDot[2] + (k1[2] * h / 2)
radius = np.sqrt((XYZ2[0]**2)+(XYZ2[1]**2)+(XYZ2[2]**2))
....
There is more code however I want to limit what I show for now since it's the intermediate steps I'm most interested in resolving. Basically, for those familiar with state vectors and using RK4, you can see that the position and velocity is updated in the intermediate step, but not the acceleration. My question is related to the calculation required in order to update too the acceleration. It would begin:
XYZDDot[0] = ...
XYZDDot[1] = ...
XYZDDot[2] = ...
...but what exactly comes after is not very clear. Any advice welcome.
Below is the full code:
for j in h_step_values:
h = j
if h > 0:
one_way_iteration_steps = one_way_iteration_steps -1
elif h < 0:
one_way_iteration_steps = one_way_iteration_steps +1
XYZ = initial_XYZ
#if total_step_number != 0:
for i in range(0, one_way_iteration_steps):
#Calculate k1
k1[0] = (-cs.GM_GLONASS * XYZ[0] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ[0] * (1 - (5*(XYZ[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[0] + (cs.OMEGAE_DOT**2 * XYZ[0]) + (2 * cs.OMEGAE_DOT * XYZDot[1])
k1[1] = (-cs.GM_GLONASS * XYZ[1] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ[1] * (1 - (5*(XYZ[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[1] + (cs.OMEGAE_DOT**2 * XYZ[1]) - (2 * cs.OMEGAE_DOT * XYZDot[0])
k1[2] = (-cs.GM_GLONASS * XYZ[2] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ[2] * (3 - (5*(XYZ[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[2]
#Intermediate step to bridge k1 to k2
XYZ2[0] = XYZ[0] + (XYZDot[0] * h / 2) + (k1[0] * h**2 / 8)
XYZDot2[0] = XYZDot[0] + (k1[0] * h / 2)
XYZDDot2[0] = XYZDDot[0] + (k1[0] * h / 2)
XYZ2[1] = XYZ[1] + (XYZDot[1] * h / 2) + (k1[1] * h**2 / 8)
XYZDot2[1] = XYZDot[1] + (k1[1] * h / 2)
XYZ2[2] = XYZ[2] + (XYZDot[2] * h / 2) + (k1[2] * h**2 / 8)
XYZDot2[2] = XYZDot[2] + (k1[2] * h / 2)
radius = np.sqrt((XYZ2[0]**2)+(XYZ2[1]**2)+(XYZ2[2]**2))
#Calculate k2
k2[0] = (-cs.GM_GLONASS * XYZ2[0] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[0] * (1 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[0] + (cs.OMEGAE_DOT**2 * XYZ2[0]) + (2 * cs.OMEGAE_DOT * XYZDot2[1])
k2[1] = (-cs.GM_GLONASS * XYZ2[1] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[1] * (1 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[1] + (cs.OMEGAE_DOT**2 * XYZ2[1]) - (2 * cs.OMEGAE_DOT * XYZDot2[0])
k2[2] = (-cs.GM_GLONASS * XYZ2[2] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[2] * (3 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[2]
#Intermediate step to bridge k2 to k3
XYZ2[0] = XYZ[0] + (XYZDot[0] * h / 2) + (k2[0] * h**2 / 8)
XYZDot2[0] = XYZDot[0] + (k2[0] * h / 2)
XYZ2[1] = XYZ[1] + (XYZDot[1] * h / 2) + (k2[1] * h**2 / 8)
XYZDot2[1] = XYZDot[1] + (k2[1] * h / 2)
XYZ2[2] = XYZ[2] + (XYZDot[2] * h / 2) + (k2[2] * h**2 / 8)
XYZDot2[2] = XYZDot[2] + (k2[2] * h / 2)
radius = np.sqrt((XYZ2[0]**2)+(XYZ2[1]**2)+(XYZ2[2]**2))
#Calculate k3
k3[0] = (-cs.GM_GLONASS * XYZ2[0] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[0] * (1 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[0] + (cs.OMEGAE_DOT**2 * XYZ2[0]) + (2 * cs.OMEGAE_DOT * XYZDot2[1])
k3[1] = (-cs.GM_GLONASS * XYZ2[1] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[1] * (1 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[1] + (cs.OMEGAE_DOT**2 * XYZ2[1]) - (2 * cs.OMEGAE_DOT * XYZDot2[0])
k3[2] = (-cs.GM_GLONASS * XYZ2[2] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[2] * (3 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[2]
#Intermediate step to bridge k3 to k4
XYZ2[0] = XYZ[0] + (XYZDot[0] * h) + (k3[0] * h**2 / 2)
XYZDot2[0] = XYZDot[0] + (k3[0] * h)
XYZ2[1] = XYZ[1] + (XYZDot[1] * h) + (k3[1] * h**2 / 2)
XYZDot2[1] = XYZDot[1] + (k3[1] * h)
XYZ2[2] = XYZ[2] + (XYZDot[2] * h) + (k3[2] * h**2 / 2)
XYZDot2[2] = XYZDot[2] + (k3[2] * h)
radius = np.sqrt((XYZ2[0]**2)+(XYZ2[1]**2)+(XYZ2[2]**2))
#Calculate k4
k4[0] = (-cs.GM_GLONASS * XYZ2[0] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[0] * (1 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[0] + (cs.OMEGAE_DOT**2 * XYZ2[0]) + (2 * cs.OMEGAE_DOT * XYZDot2[1])
k4[1] = (-cs.GM_GLONASS * XYZ2[1] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[1] * (1 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[1] + (cs.OMEGAE_DOT**2 * XYZ2[1]) - (2 * cs.OMEGAE_DOT * XYZDot2[0])
k4[2] = (-cs.GM_GLONASS * XYZ2[2] / radius**3) \
+ ((3/2) * cs.C_20 * cs.GM_GLONASS * cs.SEMI_MAJOR_AXIS_GLONASS**2 * XYZ2[2] * (3 - (5*(XYZ2[2]**2) / (radius**2))) / radius**5) \
+ XYZDDot[2]
for p in range(3):
XYZ[p] = XYZ[p] + XYZDot[p] * h + h**2 * ((k1[p] + 2*k2[p] + 2*k3[p] + k4[p]) / 12)
XYZDot[p] = XYZDot[p] + (h * (k1[p] + 2*k2[p] + 2*k3[p] + k4[p]) / 6)
radius = np.sqrt((XYZ[0])**2 + (XYZ[0])**2 + (XYZ[0])**2)
The equation you are solving is of the type
ddot x = a(x)
where a(x) is the acceleration which is computed in your k1 computation. Indeed, the first order system would be
dot v = a(x)
dot x = v
The RK4 implementation thus starts with
k1 = a(x)
l1 = v
k2 = a(x+l1*h/2) = a(x+v*h/2)
l2 = v+k1*h/2
etc. The use of the l1,l2,... seems implicit in the code, inserting these linear combinations directly where they occur.
In short, you are not missing the acceleration computation, it is the main part of the code fragment.
Update: (8/22) To come closer to the intention of the intermediate bridge steps, the abstract code should read ( with (* .. *) denoting comments or unnecessary computations)
k1 = a(x) (* l1 = v *)
x2 = x + v*h/2 (* v2 = v + k1*h/2 *)
k2 = a(x2) (* l2 = v2 *)
x3 (* = x + l2*h/2 *)
= x + v*h/2 + k1*h^2/4 (* v3 = v + k2*h/2 *)
k3 = a(x3) (* l3 = v3 *)
x4 (* = x + l3*h *)
= x + v*h + k2*h^2/2 (* v4 = v + k3*h *)
k4 = a(x4) (* l4 = v4 *)
delta_v = ( k1+2*(k2+k3)+k4 ) * h/6
delta_x (* = ( l1+2*(l2+l3)+l4 ) * h/6 *)
= v*h + (k1+k2+k3) * h^2/6
Related
How i can shorten code for neural-network?
I wrote a neural network and after that, i want to write neural network bigger than it, and i dont want to write too big code input[0] = (player_x - Game_logic.block_1x) input[1] = (player_y - Game_logic.block_1y) input[2] = (player_x - Game_logic.block_2x) input[3] = (player_y - Game_logic.block_2y) input[4] = (player_x - Game_logic.block_3x) input[5] = (player_y - Game_logic.block_3y) snk[0] = (((input[0] * weights[0])/10) + ((input[1] * weights[1])/10) + ((input[2] * weights[2])/10) + ((input[3] * weights[3])/10) + ((input[4] * weights[4])/10) + ((input[5] * weights[5])/10) +1) snk[1] = (((input[0] * weights[6])/10) + ((input[1] * weights[7])/10) + ((input[2] * weights[8])/10) + ((input[3] * weights[9])/10) + ((input[4] * weights[10])/10) + ((input[5] * weights[11])/10) +1) snk[2] = (((input[0] * weights[12])/10) + ((input[1] * weights[13])/10) + ((input[2] * weights[14])/10) + ((input[3] * weights[15])/10) + ((input[4] * weights[16])/10) + ((input[5] * weights[17])/10) +1) snk[3] = (((input[0] * weights[18])/10) + ((input[1] * weights[19])/10) + ((input[2] * weights[20])/10) + ((input[3] * weights[21])/10) + ((input[4] * weights[22])/10) + ((input[5] * weights[23])/10) +1) snk[4] = (((input[0] * weights[24])/10) + ((input[1] * weights[25])/10) + ((input[2] * weights[26])/10) + ((input[3] * weights[27])/10) + ((input[4] * weights[28])/10) + ((input[5] * weights[29])/10) +1) output[0] = ((snake_layer_1[0] * weights[30])/10) + ((snake_layer_1[1] * weights[31])/10) + ((snake_layer_1[2] * weights[32])/10) + ((snake_layer_1[3] * weights[33])/10) + ((snake_layer_1[4] * weights[34])/10) output[1] = ((snake_layer_1[0] * weights[35])/10) + ((snake_layer_1[1] * weights[36])/10) + ((snake_layer_1[2] * weights[37])/10) + ((snake_layer_1[3] * weights[38])/10) + ((snake_layer_1[4] * weights[39])/10) output[3] = ((snake_layer_1[0] * weights[40])/10) + ((snake_layer_1[1] * weights[41])/10) + ((snake_layer_1[2] * weights[42])/10) + ((snake_layer_1[3] * weights[43])/10) + ((snake_layer_1[4] * weights[44])/10)
Numerical instability in python
I am trying to make several plots for a project of mine using the following code: import pprint import scipy import scipy.linalg # SciPy Linear Algebra Library import numpy as np from scipy.linalg import lu , lu_factor, lu_solve from scipy.integrate import quad import matplotlib.pyplot as plt #Solving the equations for the Prandtl case K = 100 alpha = 0.1 visc = 5 diff = 5 N = 0.01 L = 5000 height = 250 subdivisions = 100 tick = 10 points = np.arange(0,L/2+tick,tick) def H(y): return ( height * (1 + np.cos(2 * np.pi * y/L)) ) def Bsfc(y): return 0.1 final_system = [] b=[] for q in range(-K,K+1): equation1 = [] equation2 = [] equation3 = [] Aki = [] Cki = [] Dki = [] for k in range(-K,K+1): R = 2 * N**2 * np.cos(alpha)**2 / (visc * diff) * (k * np.pi / L)**2 Q = N**2 * np.sin(alpha)**2 / (3 * visc * diff) S1 = abs(R + np.sqrt(Q**3 + R**2) )**(1/3) S2 = - abs( np.sqrt(Q**3 + R**2) -R )**(1/3) phi = np.sqrt(S1**2 + S2**2 - S1*S2) Lk = np.arccos(- (S1 + S2)/ (2 * phi) ) m1 = - np.sqrt(S1 + S2) m2 = - np.sqrt(phi) * np.exp(1j * Lk/2) m3 = m2.conjugate() def f1r(y): return (np.exp(m1 * H(y)) * np.cos(2 * (q - k) * np.pi * y / L) ).real def f1i(y): return (np.exp(m1 * H(y)) * np.cos(2 * (q - k) * np.pi * y / L) ).imag gamma1 = 2/L * (quad(f1r,0,L/2,limit=subdivisions)[0] + quad(f1i,0,L/2,limit=subdivisions)[0]*1j) def f2r(y): return (np.exp(m2 * H(y)) * np.cos(2 * (q - k) * np.pi * y / L) ).real def f2i(y): return (np.exp(m2 * H(y)) * np.cos(2 * (q - k) * np.pi * y / L) ).imag gamma2 = 2/L * (quad(f2r,0,L/2,limit=subdivisions)[0] + quad(f2i,0,L/2,limit=subdivisions)[0]*1j) if k == 0: equation1.append(2 * gamma2.real) Cki.append(k) equation1.append(-2 * gamma2.imag) Dki.append(k) else: equation1.append(gamma1) Aki.append(k) equation1.append(2 * gamma2.real) Cki.append(k) equation1.append(-2 * gamma2.imag) Dki.append(k) if q != 0: if k == 0: equation2.append(0) equation2.append(0) else: equation2.append(k * gamma1 / (m1**3) ) equation2.append(2 * k * (gamma2 / (m2**3) ).real) equation2.append(-2 * k * (gamma2 / (m2**3) ).imag) if k == 0: equation3.append(2 * (m2**2 * gamma2).real) equation3.append(-2 * (m2**2 * gamma2).imag) else: equation3.append(m1**2 * gamma1) equation3.append(2 * (m2**2 * gamma2).real) equation3.append(-2 * (m2**2 * gamma2).imag) final_system.append(equation1) def f4r(y): return (Bsfc(y) * np.cos(2 * q * np.pi * y / L) ).real def f4i(y): return (Bsfc(y) * np.cos(2 * q * np.pi * y / L) ).imag b.append(2/L * (quad(f4r,0,L/2,limit=subdivisions)[0] + quad(f4i,0,L/2,limit=subdivisions)[0]*1j)) if q != 0: final_system.append(equation2) b.append(0) final_system.append(equation3) b.append(0) final_system = np.array(final_system) b=np.array(b) #LU solver P, Ls, U = scipy.linalg.lu(final_system) Bl = np.linalg.inv(P) # b Z = np.linalg.solve(Ls,Bl) X = np.linalg.solve(U,Z) print (np.allclose(final_system # X, b)) #Getting the values for Ak, Ck and Dk strings = [] for k in range(-K,K+1): if k != 0: strings.append('A') strings.append('R') strings.append('I') Ak = [] Rk = [] Ik = [] for k in range(0,len(X)): if 'A' in strings[k]: Ak.append(X[k]) if 'R' in strings[k]: Rk.append(X[k]) if 'I' in strings[k]: Ik.append(X[k]) Ck=[] for k in range(0,len(Rk)): Ck.append(Rk[k] + Ik[k] * 1j) Ck = np.array(Ck) Dk = Ck.conjugate() Ak = np.array(Ak) #Getting the Buoyancy value z = np.arange(0,2010,10) y = np.arange(-L,L+10,10) Y,Z = np.meshgrid(y,z) B = np.ones_like(Y)*[0] for k in range(-K,K+1): R = 2 * N**2 * np.cos(alpha)**2 / (visc * diff) * (k * np.pi / L)**2 Q = N**2 * np.sin(alpha)**2 / (3 * visc * diff) S1 = abs(R + np.sqrt(Q**3 + R**2) )**(1/3) S2 = - abs( np.sqrt(Q**3 + R**2) -R )**(1/3) phi = np.sqrt(S1**2 + S2**2 - S1*S2) Lk = np.arccos(- (S1 + S2)/ (2 * phi) ) m1 = - np.sqrt(S1 + S2) m2 = -np.sqrt(phi) * np.exp(1j * Lk/2) m3 = m2.conjugate() if k != 0: B = B + ( Ak[Aki.index(k)] * np.exp(m1 * Z) * np.exp(2j * (k) * np.pi * Y / L) ) B = B + ( ( Ck[Cki.index(k)] * np.exp(m2 * Z) + Dk[Dki.index(k)] * np.exp(m3 * Z) ) * np.exp(2j * (k) * np.pi * Y / L) ) for k in range(0,B.shape[0]): for t in range(0,B.shape[1]): if Z[k][t] < H(Y[k][t]): B[k][t] = np.nan if Z[k][t] == H(Y[k][t]): print (B[k][t], "B value at the ground") if abs(Z[k][t] - H(Y[k][t])) < 0.1: if B[k][t] > 0.101: print (B[k][t],'error -------------------------------------------------') # print (B[k][t], Z[k][t], H(Y[k][t]), Y[k][t], '-----------------------------------------------------------------------------' ) Bp = Bsfc(Y) * np.exp(-Z * np.sqrt(N * np.sin(alpha) ) / (4*visc*diff)**(1/4) ) * np.cos(np.sqrt(N*np.sin(alpha)) /((4*visc*diff)**(1/4))*Z ) ##Plotting the buoyancy fig = plt.figure(figsize=(10,10)) # create a figure plt.rcParams.update({'font.size':16}) plt.title('Buoyancy') plt.contourf(Y,Z,B,np.arange(-0.2,0.201,0.001),cmap='seismic') #plt.contourf(Y,Z,B,cmap='seismic') plt.colorbar(label='1/s') plt.xlabel("Y axis") plt.ylabel("Height") plt.xlim([-L,L]) plt.ylim([0,1500]) plt.show() The following plot shows a run that yielded a good result: Buoyancy However, when I increase the "height" parameter, I start getting unstable results, which I suspect occurs because of numerical instabilities: Buoyancy unstable Is there a way to increase numerical precision in python? I have experimented a bit with numpy.double, but with unsuccessful results so far. Thanks
I guess you'll find your answer here on Stackoverflow In the standard library, the decimal module may be what you're looking for. Also, I have found mpmath to be quite helpful...
Questions about accessing index of Gekko array in Python
I'm currently having some issue regarding accessing indices in Gekko array. I'm trying to convert following code: m = GEKKO() s42 = m.Array(m.Var, 8) s44 = m.Array(m.Var, 8) m.Equation(s42[0] == p42_raw[0] / (n34 + n44) * (n34 * (p34_norm[0] + p34_norm[4]) + n44 * (s44[0] + s44[4]) / np.sum(s44))) m.Equation(s42[1] == p42_raw[1] / (n34 + n44) * (n34 * (p34_norm[0] + p34_norm[4]) + n44 * (s44[0] + s44[4]) / np.sum(s44))) m.Equation(s42[2] == p42_raw[2] / (n34 + n44) * (n34 * (p34_norm[1] + p34_norm[5]) + n44 * (s44[1] + s44[5]) / np.sum(s44))) m.Equation(s42[3] == p42_raw[3] / (n34 + n44) * (n34 * (p34_norm[1] + p34_norm[5]) + n44 * (s44[1] + s44[5]) / np.sum(s44))) m.Equation(s42[4] == p42_raw[4] / (n34 + n44) * (n34 * (p34_norm[2] + p34_norm[6]) + n44 * (s44[2] + s44[6]) / np.sum(s44))) m.Equation(s42[5] == p42_raw[5] / (n34 + n44) * (n34 * (p34_norm[2] + p34_norm[6]) + n44 * (s44[2] + s44[6]) / np.sum(s44))) m.Equation(s42[6] == p42_raw[6] / (n34 + n44) * (n34 * (p34_norm[3] + p34_norm[7]) + n44 * (s44[3] + s44[7]) / np.sum(s44))) m.Equation(s42[7] == p42_raw[7] / (n34 + n44) * (n34 * (p34_norm[3] + p34_norm[7]) + n44 * (s44[3] + s44[7]) / np.sum(s44))) ... to something shorter like below: m.Equation([s42[i] for i in range(8)] == [p42_raw[i] / (n34 + n44) * (n34 * (p34_norm[np.uint(i / 2)] + p34_norm[np.uint(4 + i / 2)]) + n44 * (s44[np.uint(i / 2)] + s44[np.uint(4 + i / 2)]) / sum(s44)) for i in range(8)]) but currently getting following errors: File "/Users/tomino/opt/anaconda3/lib/python3.7/site-packages/gekko/gk_operators.py", line 144, in __len__ return len(self.value) TypeError: object of type 'int' has no len() I've been stuck in this problem for a while but cannot find any suitable solution yet. Can anyone please help me resolving this issue?
Isn't this what you're after? for i in range(8): h = i // 2 m.Equation(s42[i] == p42_raw[i] / (n34 + n44) * (n34 * (p34_norm[h] + p34_norm[h+4]) + n44 * (s44[h] + s44[h+4]) / np.sum(s44)))
Understanding timesteps in scipy.integrate.odeint
I am trying to solve a PDE using odeint and the method of lines. My code is definitely wrong - and I'm trying to figure out where it is going wrong. I am calling the ode solver using odeint(odefunc,y0,tspan) where tspan = np.linspace(0.0, 0.5, 5) & y0 = 1.0*np.ones(3). I tried printing t within odefunc and am confused by the output. Despite the fact that I am solving up to t=0.5, the last t-value to print is 0.015081203121127767. The number of outputs matches tspan, but I cannot see how it could possibly be solving up to t = 0.5 when the last time in the de function is 0.015. What am I missing? My DE is time dependent - so this is making it very hard to figure out where things are going wrong because I don't seem to be seeing the times where everything fails. ETA - this is failing, but running this without some of the irrelevant stuff I am getting the warning ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information., which I'm assuming is part of the issue - but it doesn't appear to be halting the code. MWE import numpy as np from scipy.integrate import odeint import matplotlib.pyplot as plt import math import sys plt.interactive(False) sigma = 2320 rho = 1000 gravity = 9.81 # [m/s^2] g = gravity*3600*3600 # [m/hour^2] S = 0.01 settlingVelocity = 0.02 # [m/s] ws = settlingVelocity*3600 # [m/hour] n = 0.04 # [SI] J = 400 # [Ws/m] k = 0.02 Cstar = 0.2 * sigma # [kg/m^3] W = 2 # [m] D0 = 1.2 Lw = 20 L = 100 tend = 0.5 # in hours tspan = np.linspace(0.0, tend, 5) def d(t): # metres if t < 50: # hours return 0.5 else: return 0.05 def Q(t): return 3600 * (math.sqrt(S)/n)*((W*d(t))**(5/3))/((2*d(t) + W)**(2/3)) def h(t): return d(t)/2 def beta(t): return (sigma - rho) * g * h(t)/sigma def Omega(t): return rho * g * S * Q(t) # [W/m] def PsiTime(t): return rho * g * Q(t) * (D0 - d(t))/(Lw) N = 10 X = np.linspace(0, L, N) delX = L/ (N-1) def odefunc(y, t): def zetaEh(t): return k * (PsiTime(t) + Omega(t)) / (J + beta(t)) def zetaEW(t): return (2*d(t)/(W + 2*d(t))) * k * Omega(t)/(J + beta(t)) def zetaR(t): return (W/(W + 2*d(t))) * k*Omega(t)/(beta(t)) def zetaEF(t,i): return (W/(W + 2*d(t))) * k * Omega(t) / (J + beta(t)) C = y[:N] M = y[N:] print("time: ", t) dCdt = np.zeros(X.shape) dMdt = np.zeros(X.shape) dCdt[0] = ( # forward difference for dCdx -Q(t) / (W*d(t)) * (C[1] - C[0]) / delX + (zetaEh(t) / (W * d(t))) * ((Cstar - C[0]) / Cstar) - (ws * C[0] * (beta(t))) / (d(t) * (J + beta(t))) ) dMdt[0] = 0 # gully channel for i in range (1, N-1): # central difference if M[i] + W *C[i] * ws - zetaR(t) * (Cstar - C[i]) / Cstar < 0: reMass = M[i] + W * C[i] * ws dCdt[i] = ( -Q(t) / (W*d(t)) * (C[i+1] - C[i - 1]) / (2*delX) + 1 / (W * d(t)) * ((zetaEW(t) + zetaEF(t,i)) * (Cstar - C[i]) / Cstar + reMass * (1 - (beta(t))/ (J + beta(t)))) - C[i] * ws/d(t) ) dMdt[i] = -M[i] else: dCdt[i] = ( -Q(t) / (W*d(t)) * (C[i+1] - C[i - 1]) / (2*delX) + 1 / (W * d(t)) * (zetaEW(t) + zetaR(t)) * (Cstar - C[i]) / Cstar - C[i] * ws / d(t) ) dMdt[i] = W * C[i] * ws - zetaR(t) * (Cstar - C[i]) / Cstar # Final node - backward difference if M[N-1] + W * C[N-1] * ws - zetaR(t) * (Cstar - C[N-1]) / Cstar < 0: reMass = M[N-1] + W * C[N-1] * ws dCdt[N-1] = ( -Q(t) / (W * d(t)) * (C[N-1] - C[N-2]) / delX + 1 / (W * d(t)) * ((zetaEW(t) + zetaEF(t, i)) * (Cstar - C[N-1]) / Cstar + reMass * (1 - (beta(t)) / (J + beta(t)))) - C[i] * ws / d(t) ) dMdt[N-1] = -M[N-1] else: dCdt[N-1] = ( -Q(t) / (W * d(t)) * (C[N-2] - C[N - 1]) / delX + 1 / (W * d(t)) * (zetaEW(t) + zetaR(t)) * (Cstar - C[N-1]) / Cstar - C[N-1] * ws / d(t) ) dMdt[N-1] = W * C[N-1] * ws - zetaR(t) * (Cstar - C[N-1]) / Cstar dydt = np.ravel([dCdt, dMdt]) return dydt init_C = 0.0 * np.ones(X.shape) init_M = 0.0 * np.ones(X.shape) init= np.ravel([init_C, init_M]) sol = odeint(odefunc, init, tspan) conc = sol[:, :N]
How to Check if Jacobian is Correct
I am happily integrating a simple ODE with scipy.odeint. This is my integration fuction: def f(self, x, t_0): h = x[0:3] f = x[3:6] der = [] der.append((self.q_0 - f[0] * self.u[0] * self.k[0] * numpy.sign(h[0] - h[1]) * numpy.sqrt(abs(h[0] - h[1]))) / self.A[0]) der.append((f[0] * self.u[0] * self.k[0] * numpy.sign(h[0] - h[1]) * numpy.sqrt(abs(h[0] - h[1])) - f[1] * self.u[1] * self.k[1] * numpy.sign(h[1]) * numpy.sqrt(abs(h[1]))) / self.A[1]) der.append((f[1] * self.u[1] * self.k[1] * numpy.sign(h[1] - h[2]) * numpy.sqrt(abs(h[1] - h[2])) - f[2] * self.u[2] * self.k[2] * numpy.sign(h[2]) * numpy.sqrt(abs(h[2]))) / self.A[2]) der.append(0) der.append(0) der.append(0) return numpy.array(der) Everything works fine if I call scipy.integrate.odeint except I decided to provide the Jacobian so I can do the integration faster. This is the Jacobian which I figured out by hand: def F(self, x, t_0): h = x[0:3] f = x[3:6] u = self.u k = self.k A = self.A result = numpy.zeros((6, 6)) sqrt_diff_h0_h1 = numpy.sign(h[0] - h[1]) * numpy.sqrt(abs(h[0] - h[1])) sqrt_diff_h1_h2 = numpy.sign(h[1] - h[2]) * numpy.sqrt(abs(h[1] - h[2])) sqrt_diff_h1 = numpy.sign(h[1]) * numpy.sqrt(abs(h[1])) sqrt_diff_h2 = numpy.sign(h[2]) * numpy.sqrt(abs(h[2])) result[0][0] = -(u[0] * f[0] * k[0]) / (2 * A[0] * sqrt_diff_h0_h1) result[0][1] = (u[0] * f[0] * k[0]) / (2 * A[0] * sqrt_diff_h0_h1) result[0][3] = -(u[0] * k[0] * sqrt_diff_h0_h1) / A[0] result[1][0] = (u[0] * f[0] * k[0]) / (2 * A[1] * sqrt_diff_h0_h1) result[1][1] = -((u[0] * f[0] * k[0] * A[1]) / (2 * sqrt_diff_h0_h1)) - \ ((u[1] * f[1] * k[1] * A[1]) / (2 * sqrt_diff_h1)) result[1][3] = (u[0] * k[0] * sqrt_diff_h0_h1) / A[1] result[1][4] = -(u[1] * k[1] * sqrt_diff_h1) / A[1] result[2][1] = (u[1] * f[1] * k[1]) / (2 * A[2] * sqrt_diff_h1_h2) result[2][2] = -((u[1] * f[1] * k[1] * A[2]) / (2 * sqrt_diff_h1_h2)) - \ ((u[2] * f[2] * k[2] * A[2]) / (2 * sqrt_diff_h2)) result[2][4] = (u[1] * k[1] * sqrt_diff_h1_h2) / A[2] result[2][5] = -(u[2] * k[2] * sqrt_diff_h2) / A[2] return result If I supply F to scipy.odeint.integrate, it actually takes more time. This, of course, doesn't mean much but I am wondering how to determine if the Jacobian is correct? I need it for other purposes of linearization.