I want to have the pendulum blob in my double pendulum - python

In this code I want to have animation something like this. But I dont want the other pendulums that come into picture later. Just the initial one. Currently this is my output. This is the image after the animation completes. In the animation, I want to have a ball(blob) which plots the red lines and another one which plots the green lines.
import numpy as np
from numpy import cos, sin, arange, pi
import matplotlib.pyplot as plt
import matplotlib.animation as animation
h = 0.0002 #the change in runge kutta
figsize = 6
dpi = 1000
N = 200000 # iterations
L1=1 #length 1
L2=1.5 #lenth 2
m1=50 #mass of bob 1
m2=1 #mass of bob2
g = 9.81#gravity
theta_01 = (np.pi/180)*90
theta_02 = (np.pi/180)*60
w_1 = 0
w_2 = 0
# dw/dt function oft theta 1
def funcdwdt1(theta1,theta2,w1,w2):
cos12 = cos(theta1 - theta2)#for wrirting the main equation in less complex manner
sin12 = sin(theta1 - theta2)
sin1 = sin(theta1)
sin2 = sin(theta2)
denom = cos12**2*m2 - m1 - m2
ans = ( L1*m2*cos12*sin12*w1**2 + L2*m2*sin12*w2**2
- m2*g*cos12*sin2 + (m1 + m2)*g*sin1)/(L1*denom)
return ans
# dw/dt function oft thetas 2
def funcdwdt2(theta2,theta1,w1,w2):
cos12 = cos(theta1 - theta2)
sin12 = sin(theta1 - theta2)
sin1 = sin(theta1)
sin2 = sin(theta2)
denom = cos12**2*m2 - m1 - m2
ans2 = -( L2*m2*cos12*sin12*w2**2 + L1*(m1 + m2)*sin12*w1**2
+ (m1 + m2)*g*sin1*cos12 - (m1 + m2)*g*sin2 )/(L2*denom)
return ans2
# d0/dt function for theta 1
def funcd0dt1(w0):
return w0
# d0/dt function for theta 2
def funcd0dt2(w0):
return w0
X1= []
X2= []
Y1= []
Y2= []
def func(w1,w2, theta1,theta2):
for i in range(N):
k1a = h * funcd0dt1(w1) # gives theta1
k1b = h * funcdwdt1(theta1,theta2,w1,w2) # gives omega1
k1c = h * funcd0dt2(w2) # gives theta2
k1d = h * funcdwdt2(theta2,theta1,w1,w2) # gives omega2
k2a = h * funcd0dt1(w1 + (0.5 * k1b))
k2b = h * funcdwdt1(theta1 + (0.5 * k1a),theta2,w1,w2)
k2c = h * funcd0dt2(w2 + (0.5 * k1d))
k2d = h * funcdwdt2(theta2 + (0.5 * k1c),theta1,w1,w2)
k3a = h * funcd0dt1(w1 + (0.5 * k2b))
k3b = h * funcdwdt1(theta1 + (0.5 * k2a),theta2,w1,w2)
k3c = h * funcd0dt2(w2 + (0.5 * k2d))
k3d = h * funcdwdt2(theta2 + (0.5 * k2c),theta1,w1,w2)
k4a = h * funcd0dt1(w1 + k3b)
k4b = h * funcdwdt1(theta1 + k3a,theta2,w1,w2)
k4c = h * funcd0dt2(w2 + k3d)
k4d = h * funcdwdt2(theta2 + k3c,theta1,w1,w2)
#addidng the vakue aftyer the iterartions
theta1 += 1 / 6 * (k1a + 2 * k2a + 2 * k3a + k4a)
w1 +=1 / 6 * (k1b + 2 * k2b + 2 * k3b + k4b)
theta2 += + 1 / 6 * (k1c + 2 * k2c + 2 * k3c + k4c)
w2 += 1 / 6 * (k1d + 2 * k2d + 2 * k3d + k4d)
x1 = L1 * sin(theta1)
y1 = -L1 * cos(theta1)
x2 = x1 + L2 * sin(theta2)
y2 = y1 - L2 * cos(theta2)
X1.append(x1)
X2.append(x2)
Y1.append(y1)
Y2.append(y2)
return x1,y1,x2,y2
print(func(w_1, w_2, theta_01, theta_02))
fig, ax = plt.subplots()
l1, = ax.plot([], [])
l2, = ax.plot([],[])
ax.set(xlim=(-3, 3), ylim=(-2,2))
def animate(i):
l1.set_data(X1[:i], Y2[:i])
l2.set_data(X2[:i], Y2[:i])
return l1,l2,
ani = animation.FuncAnimation(fig, animate, interval = 5, frames=len(X1))
# plt.show()
ani.save('save.mp4', writer='ffmpeg')

Just add another line
l3, = ax.plot([],[], '-ob', lw=2, ms=8)
and in the animate function set its values to
l3.set_data([0,X1[i],X2[i]], [0,Y1[i],Y2[i]])
Adapt line-width and marker-size as necessary. This should draw filled circles at the pendulum positions and the origin with lines connecting them.
You should use Y1 in the l1 data. With a total pendulum length of 2.5, the vertical limits are too small. It is sufficient to use
h = 0.005 #the change in runge kutta
N = 5000 # iterations
to get an animation with realistic speed. Or combine several RK4 steps for each frame. For minimum error you can use h=1e-3, smaller step sizes only lead to the accumulation of floating point errors dominating the method error.

Related

How could I make a line which is inverted to the original

At the moment this is my code:
import scipy
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import EventCollection
import math
from scipy import integrate
from scipy import constants
K_b = 1.380649e-23 # Boltzmanns Constant
a_n = 6.022e23 # Avogrados Number
T = 10 # Kelvin
mass = 28
a = 10e-5
def mantleEvolution(tMax, dt) :
N = int(tMax/dt) + 1
timeArray = np.zeros(N)
numberArray = np.zeros(N)
t = 0
n_m = 1 #per cubic centimeter
n_s = 0
i = 0
while i < N:
m_m = float(mass) / a_n
V_m = math.sqrt((8.0 * K_b * float(T)) / (math.pi * float(m_m)))
R = math.pi * pow(float(a), 2) * n_m * V_m
ρ_d = 3 # g/cm^3
μ_g = 2 * 1.67e-23
m_d = (4 / 3) * math.pi * pow(float(a), 3)
n_g = 10e4
d_g = 0.01 # 1% mass density of gas
n_d = (d_g * n_g * μ_g) / (m_d * float(ρ_d))
n_s = n_s + R * dt
n_m = n_m - R * n_d * dt
timeArray[i] = t
numberArray[i] = n_m
t = t + dt
i = i + 1
return [timeArray, numberArray, n_s]
timeArray, numberArray, n_s = mantleEvolution(5.0 * 10**15, 5.0 * 10**9)
fig = plt.figure(figsize=(6.4, 6.4))
ax1 = plt.subplot(111)
ax1.plot(timeArray, numberArray)
ax1.set_xlabel('time, seconds', fontsize=20)
ax1.set_ylabel('number', fontsize=20)
plt.setp(ax1.get_xticklabels(), fontsize=16)
plt.setp(ax1.get_yticklabels(), fontsize=16)
fig.subplots_adjust(left=.18)
plt.savefig('mantleEvolution.pdf')
This is the graph I recieve from graphing my code:
What I wish to find out is how I could plot a second line which behaves the exact opposite where it grows at the same rate the other declines
So for example, something that ressembles this:
If you look at the graph you'll see that the value on the y axis is for both graphs the same for two opposite x values at the x axis. That means that all you want to do is invert the x axis. That is fairly easy done using the formula:
new_x = -1 * (old_x - 2.5) + 2.5
By the way, I see some interesting comments in your code. What is it that you are trying to do here if I may ask?

How to get Stochastic Gradient Descent result in contour plot

import numpy as np
from matplotlib import pyplot as plt
xk = np.linspace(-1,1,100)
yk= 2 * xk + 3 + np.random.rand(len(xk))
x1,x2 = np.meshgrid(xk,yk)
F = (x1 - 2) ** 2 + 2 * (x2 - 3) ** 2
fig=plt.figure()
surf = fig.add_subplot(1,1,1, projection='3d')
surf.plot_surface(x1,x2,F)
surf.contour(x1,x2,F)
fig, surf=plt.subplots()
plt.contour(x1, x2, F, 20)
m = 0
c = 0
learning_rate=0.01
I think my problem to get the correct result is from here, but I cant find where is the problem
for k in range(10):
shuffel_index=np.random.permutation(len(xk))
xk = xk[shuffel_index]
yk = yk[shuffel_index]
for i in range(len(xk)):
grad_m = - 2 * xk[i] * (yk[i] - (np.dot(m,xk[i]) + c))
grad_c = - 2 * (yk[i] - (np.dot(m,xk[i])+c))
m = m - learning_rate * grad_m
c = c - learning_rate * grad_c
surf.plot(np.array([xk[0], yk[0]]),np.array([xk[1], yk[1]]),'ko-')
if (k != 10 or i != len(xk)):
surf.plot(np.array([xk[0], yk[0]]),np.array([xk[1], yk[1]]),'ko-')
plt.show()
This is my result for the above code
And I wish to get the result like I do for gradient descent algorithm. The example of my gradient descent result.
May I know where is my error?

Compute Fourier Series for a discrete set of points

I'm trying to compute the continuous function hidden behind the points, but it shows a graph that looks like it actually coutns the points in-between as zeros.
Here's the plot that shows up (100 vectors, red dots - data set, blue plot - my Fourier series):
Here's the python code:
import matplotlib.pyplot as plt
import numpy as np
import math
step = (np.pi * 2) / 5
start = -np.pi
xDiscrete = [start, start + step, start + 2 * step, start + 3 * step, start + 4 * step, np.pi]
yDiscrete = [2.88, 2.98, 3.24, 3.42, 3.57, 3.79]
ak = []
bk = []
a0 = 0
precisionSize = 0.001
n = 100
avgError = 0
def getAN(k):
sum = 0
for ind in range(1, len(yDiscrete)):
sum += yDiscrete[ind] * math.cos(k * xDiscrete[ind])
an = (2.0 / n) * sum
print('a' + str(k) + ' = ' + str(an))
return an
def getBN(k):
sum = 0
for ind in range(1, len(yDiscrete)):
sum += yDiscrete[ind] * math.sin(k * xDiscrete[ind])
bn = (2.0 / n) * sum
print('b' + str(k) + ' = ' + str(bn))
return bn
def getA0():
sum = 0
for ind in range(1, len(yDiscrete)):
sum += yDiscrete[ind]
a0 = (2.0 / n) * sum
print('a0 = ' + str(a0))
return a0
def getFourierOneSum(x, i):
return ak[i - 1] * math.cos(i * x) + bk[i - 1] * math.sin(i * x)
def getFourierAtPoint(x):
sum = a0 / 2
for i in range(1, n + 1):
sum += getFourierOneSum(x, i)
return sum
for i in range(1, n + 1):
ak.append(getAN(i))
bk.append(getBN(i))
a0 = getA0()
x2 = np.arange(-np.pi, np.pi, precisionSize)
y2 = []
for coor in x2:
y2.append(getFourierAtPoint(coor))
plt.plot(xDiscrete, yDiscrete, 'ro', alpha=0.6)
plt.plot(x2, y2)
plt.grid()
plt.title('Approximation')
plt.show()
I've checked where is the problem, and I'm pretty sure it's with the coefficients (functions getAN, getBN, getA0), but I'm not sure how to fix it.

How to implement shooting method with coupled ODEs

I want to simulate the laser power along a silica fiber. The ODEs and the used parameters can be found in the paper linked below. Note that I converted all units to SI units in my code. The authors of this paper named the shooting method as a way to numerically solve this equations.
The paper I am referring to can be found here: https://www.osapublishing.org/oe/fulltext.cfm?uri=oe-21-17-20090&id=260516
I tried it in python but I did not manage to implement the root-finding. I used scypi.integrate_ivp to integrate the ODEs with a first guess. If I use a small value (~500m) at fiberlength I get a result but at a higher value in the range of km the solver does not manage to finish without an error. Can somebody please tell me how I can implement the shooting method here and also how I get the same solution as in the paper?
My code:
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import odeint
from scipy.integrate import solve_ivp
from scipy.integrate import solve_bvp
from scipy.optimize import fsolve
#%% ODEs und Parameter
#constants
alpha = 10**(-0.25/10)/1000 #fiber loss [1/m]
a0= alpha
a1= alpha
a2= alpha
a3= alpha
g = 0.53e-3 #RamanGain [1/(W*m)]
g1= g
g2= g*0.8
g3= g*0.6
epsilon0 = 1e-4*1e-3 #Rayleigh-scattering [1/m] REFERENZ: Paper: Third order random lasing via Raman gain and Rayleigh backscattering
epsilon1 = 5e-5*1e-3
epsilon2 = 2e-5*1e-3
epsilon3 = 1e-5*1e-3
wl_start = 1365e-9
RamanShift= 13.2e12
f0=3e8/wl_start
f1= f0 - RamanShift
f2= f1 - RamanShift
f3= f2 - RamanShift
#R_L1 = 0.99 # Reflexionskoeffizienten (Fasereingang FBG)
#R_L2 = 5e-3 # Reflexionskoeffizienten (Fasereingang)
#R_R1 = 4e-5 # Reflexionskoeffizienten (Faserausgang)
#R_R2 = 4e-5 # Reflexionskoeffizienten (Faserausgang)
R=0.6 # reflectivity
# G[i] = 4*h*f[i]*df[i]*(1+1/(np.exp((h*(f[i-1]-f[i]))/(K*T))-1))
h=6.63e-34 #Placksches Wirkungsquantum [Js]
K=1.38e-23 #Bolzmannkonstante [J/K]
T=300 #Temperature [K]
#df1= 0.18e12 #Bandbreite [Hz] REFERENZ: Paper: Third order random lasing via Raman gain and Rayleigh backscattering
#df2= 0.25e12
#df3= 0.25e12
#bandwidth
df1= 0.18e12
df2= 0.25e12
df3= 0.25e12
Gamma1= 4*h*f1*df1*(1+(1/(np.exp(h*(f0-f1)/(K*T))-1)))
Gamma2= 4*h*f2*df2*(1+(1/(np.exp(h*(f1-f2)/(K*T))-1)))
Gamma3= 4*h*f3*df3*(1+(1/(np.exp(h*(f2-f3)/(K*T))-1)))
#start conditions
Pin = 2.7 #W
fiberlength = 90000 #m
points = fiberlength*100
P0 = [Pin, 0, 0, 0, 0, 0, 0, 0 ]
def odes2 (z, P):
Pump_forward = P[0]
Pump_backward = P[1]
Stokes1_forward = P[2]
Stokes1_backward = P[3]
Stokes2_forward = P[4]
Stokes2_backward = P[5]
Stokes3_forward = P[6]
Stokes3_backward = P[7]
dPump_forwarddz = - a0 * Pump_forward - g1 * f0/f1 * Pump_forward * (Stokes1_forward + Stokes1_backward + Gamma1) + epsilon0 * Pump_backward
dPump_backwarddz = + a0 * Pump_backward + g1 * f0/f1 * Pump_backward * (Stokes1_forward + Stokes1_backward + Gamma1) - epsilon0 * Pump_forward
dStokes1_forwarddz = - a1 * Stokes1_forward - g2 * f1/f2 * Stokes1_forward * (Stokes2_forward + Stokes2_backward + Gamma2) + g1 * (Stokes1_forward + 0.5 * Gamma1) * (Pump_forward + Pump_backward) + epsilon1 * Stokes1_backward
dStokes1_backwardz = + a1 * Stokes1_backward + g2 * f1/f2 * Stokes1_backward * (Stokes2_forward + Stokes2_backward + Gamma2) - g1 * (Stokes1_backward + 0.5 * Gamma1) * (Pump_forward + Pump_backward) - epsilon1 * Stokes1_forward
dStokes2_forwarddz = - a2 * Stokes2_forward - g3 * f2/f3 * Stokes2_forward * (Stokes3_forward + Stokes3_backward + Gamma3) + g2 * (Stokes2_forward + 0.5 * Gamma2) * (Stokes1_forward + Stokes1_backward) + epsilon2 * Stokes2_backward
dStokes2_backwardz = + a2 * Stokes2_backward + g3 * f2/f3 * Stokes2_backward * (Stokes3_forward + Stokes3_backward + Gamma3) - g2 * (Stokes2_backward + 0.5 * Gamma2) * (Stokes1_forward + Stokes1_backward) - epsilon2 * Stokes2_forward
dStokes3_forwarddz = - a3 * Stokes3_forward + g3 * (Stokes3_forward + 0.5 * Gamma3) * (Stokes2_forward + Stokes2_backward) + epsilon3 * Stokes3_backward
dStokes3_backwardz = + a3 * Stokes3_backward - g3 * (Stokes3_backward + 0.5 * Gamma3) * (Stokes2_forward + Stokes2_backward) - epsilon3 * Stokes3_forward
return [dPump_forwarddz, dPump_backwarddz, dStokes1_forwarddz, dStokes1_backwardz, dStokes2_forwarddz, dStokes2_backwardz, dStokes3_forwarddz, dStokes3_backwardz]
sol = solve_ivp(odes2, (0, fiberlength), P0, t_eval=np.linspace(0, fiberlength, points))
Pump_f, Pump_b, Stokes1_f, Stokes1_b, Stokes2_f, Stokes2_b, Stokes3_f, Stokes3_b = sol.y
x=sol.t
plt.figure(1)
plt.title('backwards')
plt.plot(x, Pump_b, label='pump')
plt.plot(x, Stokes1_b, label='stokes#1')
plt.plot(x, Stokes2_b, label='stokes#2')
plt.plot(x, Stokes3_b, label='stokes#3')
plt.legend(loc=1, fontsize='xx-small')
plt.grid(True)
plt.figure(2)
plt.title('forwards')
plt.plot(x, Pump_f, label='pump')
plt.plot(x, Stokes1_f, label='stokes#1')
plt.plot(x, Stokes2_f, label='stokes#2')
plt.plot(x, Stokes3_f, label='stokes#3')
plt.legend(loc=1, fontsize='xx-small')
plt.grid(True)
I also tried the solve_bvp but it wasn't successfull.

How do I plot an animation and a point in the same matplotlib plot

I have created animation plot of x_graph and y_graph which plots the path of the planet and the plot of x_sun and y_sun in the same plot of x_graph and y_graph having marker = 'o', where the position is fixed for the entire animation i.e., at (-0.8,0). Also I need to show the motion of the planet as a blue dot moving around the sun leaving a small trail behind but not the complete path of its motion.
This is my code but it does not seem to work. The output is just the motion of the planet as an animation. I am not getting that blue dot from the plot of x_sun and y_sun which should be at (-0.8, 0)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
n = int(input("Enter the number of steps\n"))
s = int(n/2)
def f(r, u, t):
return 1/r**3-1/r**2 # Equation of r
def g(theta, r, t):
return 1/r**2 # Equation of theta
x_graph = []
y_graph = []
x1 = []
y1 = []
def func(r_0, theta_0, u_0, t_0, h):
x = -0.98 # initial value of x
y = 0 # initial value of y
for i in range(1, n + 1):
m1 = h * u_0
k1 = h * f(r_0, u_0, t_0)
l1 = h * g(theta_0, r_0, t_0)
m2 = h * (u_0 + 0.5 * k1)
k2 = h * f(r_0 + 0.5 * m1, u_0 + 0.5 * k1, t_0 + 0.5 * h)
l2 = h * g(theta_0 + 0.5 * l1, r_0 + 0.5 * k1, t_0 + 0.5 * h)
m3 = h * (u_0 + 0.5 * k2)
k3 = h * f(r_0 + 0.5 * m2, u_0 + 0.5 * k2, t_0 + 0.5 * h)
l3 = h * g(theta_0 + 0.5 * l2, r_0 + 0.5 * k2, t_0 + 0.5 * h)
m4 = h * (u_0 + k3)
k4 = h * f(r_0 + m3, u_0 + k3, t_0 + h)
l4 = h * g(theta_0 + l3, r_0 + k3, t_0 + h)
r_0 += (m1 + 2 * m2 + 2 * m3 + m4) / 6
u_0 += (k1 + 2 * k2 + 2 * k3 + k4) / 6
theta_0 += (l1 + 2 * l2 + 2 * l3 + l4) / 6
x = r_0 * np.cos(theta_0)
y = r_0 * np.sin(theta_0)
t_0 += h
x_graph.append(x)
y_graph.append(y)
return x, y
fig = plt.figure()
p1 = fig.add_subplot(111)
l1, = p1.plot([],[])
l2, = p1.plot([],[],marker= 'o', ls='')
print(func(0.98, -np.pi, 0, 0, 0.001))
x_sun = np.linspace(-0.8, -0.8, len(x_graph))
y_sun = np.linspace(0,0,len(y_graph))
plt.xlim(-1.2,1.5)
plt.ylim(-1.5,1.5)
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.title('Planet\'s orbit')
def polar_animator(i):
l1.set_data(x_graph[:i], y_graph[:i])
return l1,
def animate(i):
l2.set_data(x_sun[:i], y_sun[:i])
return l2,
ani = animation.FuncAnimation(fig, polar_animator, frames= len(x_graph), interval=1,
blit=True)
anim = animation.FuncAnimation(fig, animate, interval=1, blit=True)
ani.save('planet.mp4', writer= 'ffmpeg')
Currently the output looks something like this but I want to have a marker(like a big dot) at point (-0.8, 0) representing sun. Since SO doesn't allow to embed videos, I was unable to attach the video. I am attaching a .png instead
Running your code on my machine gives the following output :
A few things look out of place.
The animation is being called twice (this caused flickering in my pc). So just call the animation once and update both the elements (infact you only need to touch the sun plotting once so you can still cut on unnecessarily plotting sun every time).
def animate(i):
l2.set_data(x_sun[:i], y_sun[:i])
l1.set_data(x_graph[:i], y_graph[:i])
return l2,l1,
Call the animation func once like follows:
anim = animation.FuncAnimation(fig, animate, frames=100, interval=1, blit=True)

Categories

Resources