I'm currently working on a piece of code to model the evolution of the dark energy equation of state parameter w with the scale factor a. In order to do this I am solving a system of three coupled ODEs, however the derivative used is with respect to e-foldings N = ln(a) (in the code x = w and ln(a) = t for simplicity). I have the following code:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import math
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
def f(s,t):
p = 1.0
G = 1.0 + (1.0/p)
xm = 0
x = s[0]
y = s[1]
z = s[2]
dxdt = (x - 1.0)*(3.0*(1.0 + x) - z*math.sqrt(3.0*(1.0 + x)*y))
dydt = -3.0*(x - xm)*y*(1.0 - y)
dzdt = -math.sqrt(3.0*(1.0 + x)*y)*(G - 1.0)*(z**2)
return [dxdt, dydt, dzdt]
t = np.linspace(0.0001,1,10000)
s0 = [-0.667,0.01,0.45]
s = odeint(f,s0,t)
plt.plot(t,s[:,0],'b-')
plt.grid(True)
plt.xlabel('e-foldings, N = ln(a)')
plt.ylabel('Equation of state parameter w')
plt.show()
which gives me this plot.
This works fine, however I want the x-axis in units of a and not N = ln(a) but I can't figure out how to make it work. I've tried changing the plot line to plt.plot(math.exp(t),s[:,0],'b-') but I get the following error:
Traceback (most recent call last):
File "/Users/bradleyaldous/propr2.py", line 26, in <module>
plt.plot(math.exp(t),s[:,0],'b-')
TypeError: only size-1 arrays can be converted to Python scalars
[Finished in 6.0s]
Any help is greatly appreciated.
EDIT:
I've tried using np.exp() in the plot line like I did with the
Related
I have made the below in order to create a cube by giving different X, Y, Z values, but when I give for example (6,3,2) I don't receive 6 blocks on X-axis, 3 blocks on Y-axis, and 2 blocks on the Z-axis, but I received a cube 6x6x4, why?
import matplotlib.pyplot as plt
import numpy as np
def make(X,Y,Z):
x, y, z = np.indices((X,Y,Z))
cube2 = (x==0) & (y==0) & (z==0)
for i in range (X):
for j in range (Y):
for k in range(Z):
cube1 = (x==i) & (y==j) & (z==k)
cube2 = cube2|cube1
colors = np.ones(cube2.shape, dtype=object)
from matplotlib import cm
for i in range (X):
for j in range (Y):
for k in range(Z):
if 0<i<=3:
colors[i][j][k] = cm.gray(((i+j+k)/X),alpha=0.8)
elif 3<i<=6:
colors[i][j][k] = cm.winter(((i+j+k)/Y),alpha=0.8)
else:
colors[i][j][k] = cm.copper(((i+j+k)/Z),alpha=0.8)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.voxels(cube2, facecolors=colors, edgecolor=None)
plt.show()
make(6,3,2,)
I also need your help with something else. I have created a bezier line according to the code.
#bezier line
import numpy as np
import matplotlib.pyplot as plt
A = np.array([10,20])
B = np.array([15,8])
C = np.array([8,22])
A = A.reshape(2,1)
B = B.reshape(2,1)
C = C.reshape(2,1)
t = np.arange(0.0, 1.0, 0.1).reshape(1,-1)
P0 = A * t + (1 - t) * B
P1 = B * t + (1 - t) * C
Pfinal = P0 * t + (1 - t) * P1
x=np.transpose(Pfinal)
x1= x[:, 0]
print(x1)
plt.plot(x1)
Is it possible to implement this to the above first code in order to choose different colors instead of what I have done in the if statement? For example, on the Z axis at the right of this bezier line to have cm.winter colors, at the left cm.copper or something similar.
Your code produces the expected plots. I don't see a problem. This is not an answer but a means of showing you the plot I get with your code. What are you looking for?
make(6,3,2)
I keep getting error messages such as invalid syntax, or something is not defined.
here I defined the dependencies
import math #Basic math library
import numpy as np #Numpy -> tools for working with arrays
import matplotlib.pyplot as plt #Matplotlib -> tools for plotting
here I defined the constants
#CONSTANTS
pi = math.pi
omega_n = 30
xi = 0.05
beta = 0.1
here I defined the functions
O = (1/((1-beta**2)**2 + (2*xi*beta)**2)) #Capital Omega defined above
omega_d = omega_n*np.sqrt(1-xi**2) #Damped natural frequency
A = (2*xi*beta*np.cos(omega_n*t)*math.e**(-xi* omega_n* t)
C = 2*omega_n*(xi**2)*beta*math.e**(-xi*omega_n*t)
D = (1-beta**2)*np.sin(omega_d*t)
E = -2*xi*beta*np.cos(omega_d*t)
tmax = 60 #(sec) The max time
delta_t = 0.001 #(sec) The timestep
nPoints = tmax/delta_t #Number of equally spaced data points
t = np.linspace(0,tmax, int(nPoints)) # Time vector
ut = O* (A + omega_d + C) #Transientresponse
us = O* (D + E) #Steady-state response
rt= ut + us
plotting
#Plotting
fig = plt.figure()
axes = fig.add_axes([0.1,0.1,2,1.5])
axes.plot(t,rt,label='Respond ratio of a damped system')
axes.set_xlim([0,tmax])
axes.set_xlabel('Time (sec)')
axes.set_ylabel('Respond ratio')
axes.set_title('Respond ratio-time history')
axes.grid()
axes.legend()
plt.show()
There are several errors here. First, you're missing a bracket in this line:
A = (2*xi*beta*np.cos(omega_n*t)*math.e**(-xi* omega_n* t))
Then you're using the variable t in the same line but you haven't defined t yet. You're defining t after this line. Similarly, you need to define tmax/delta_t before using them in nPoints
My task is to do first an integration and second a trapezoid integration with Python of f(x)=x^2
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10,10)
y = x**2
l=plt.plot(x,y)
plt.show(l)
Now I want to integrate this function to get this: F(x)=(1/3)x^3 with the picture:
This should be the output in the end:
Could someone explain me how to get the antiderivative F(x) of f(x)=x^2 with python?
I want to do this with a normal integration and a trapeze integration. For trapezoidal integration from (-10 to 10) and a step size of 0.01 (width of the trapezoids). In the end I want to get the function F(x)=(1/3)x^3 in both cases. How can I reach this?
Thanks for helping me.
There are two key observations:
the trapezoidal rule refers to numeric integration, whose output is not an integral function but a number
integration is up to an arbitrary constant which is not included in your definition of F(x)
With this in mind, you can use scipy.integrate.trapz() to define an integral function:
import numpy as np
from scipy.integrate import trapz
def numeric_integral(x, f, c=0):
return np.array([sp.integrate.trapz(f(x[:i]), x[:i]) for i in range(len(x))]) + c
or, more efficiently, using scipy.integrate.cumtrapz() (which does the computation from above):
import numpy as np
from scipy.integrate import cumtrapz
def numeric_integral(x, f, c=0):
return cumtrapz(f(x), x, initial=c)
This plots as below:
import matplotlib.pyplot as plt
def func(x):
return x ** 2
x = np.arange(-10, 10, 0.01)
y = func(x)
Y = numeric_integral(x, func)
plt.plot(x, y, label='f(x) = x²')
plt.plot(x, Y, label='F(x) = x³/3 + c')
plt.plot(x, x ** 3 / 3, label='F(x) = x³/3')
plt.legend()
which provides you the desidered result except for the arbitrary constant, which you should specify yourself.
For good measure, while not relevant in this case, note that np.arange() does not provide stable results if used with a fractional step. Typically, one would use np.linspace() instead.
The cumtrapz function from scipy will provide an antiderivative using trapezoid integration:
from scipy.integrate import cumtrapz
yy = cumtrapz(y, x, initial=0)
# make yy==0 around x==0 (optional)
i_x0 = np.where(x >= 0)[0][0]
yy -= yy[i_x0]
Trapezoid integration
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10, 10, 0.1)
f = x**2
F = [-333.35]
for i in range(1, len(x) - 1):
F.append((f[i] + f[i - 1])*(x[i] - x[i - 1])/2 + F[i - 1])
F = np.array(F)
fig, ax = plt.subplots()
ax.plot(x, f)
ax.plot(x[1:], F)
plt.show()
Here I have applied the theoretical formula (f[i] + f[i - 1])*(x[i] - x[i - 1])/2 + F[i - 1], while the integration is done in the block:
F = [-333.35]
for i in range(1, len(x) - 1):
F.append((f[i] + f[i - 1])*(x[i] - x[i - 1])/2 + F[i - 1])
F = np.array(F)
Note that, in order to plot x and F, they must have the same number of element; so I ignore the first element of x, so they both have 199 element. This is a result of the trapezoid method: if you integrate an array f of n elements, you obtain an array F of n-1 elements. Moreover, I set the initial value of F to -333.35 at x = -10, this is the arbitrary constant from the integration process, I decided that value in order to pass the function near the origin.
Analytical integration
import sympy as sy
import numpy as np
import matplotlib.pyplot as plt
x = sy.symbols('x')
f = x**2
F = sy.integrate(f, x)
xv = np.arange(-10, 10, 0.1)
fv = sy.lambdify(x, f)(xv)
Fv = sy.lambdify(x, F)(xv)
fig, ax = plt.subplots()
ax.plot(xv, fv)
ax.plot(xv, Fv)
plt.show()
Here I use the symbolic math through sympy module. The integration is done in the block:
F = sy.integrate(f, x)
Note that, in this case, F and x have already the same number of elements. Moreover, the code is simpler.
I have written this code to model the motion of a spring pendulum
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib.pyplot as plt
def deriv(z, t):
x, y, dxdt, dydt = z
dx2dt2=(0.415+x)*(dydt)**2-50/1.006*x+9.81*cos(y)
dy2dt2=(-9.81*1.006*sin(y)-2*(dxdt)*(dydt))/(0.415+x)
return np.array([x,y, dx2dt2, dy2dt2])
init = array([0,pi/18,0,0])
time = np.linspace(0.0,10.0,1000)
sol = odeint(deriv,init,time)
def plot(h,t):
n,u,x,y=h
n=(0.4+x)*sin(y)
u=(0.4+x)*cos(y)
return np.array([n,u,x,y])
init2 = array([0.069459271,0.393923101,0,pi/18])
time2 = np.linspace(0.0,10.0,1000)
sol2 = odeint(plot,init2,time2)
plt.xlabel("x")
plt.ylabel("y")
plt.plot(sol2[:,0], sol2[:, 1], label = 'hi')
plt.legend()
plt.show()
where x and y are two variables, and I'm trying to convert x and y to the polar coordinates n (x-axis) and u (y-axis) and then graph n and u on a graph where n is on the x-axis and u is on the y-axis. However, when I graph the code above it gives me:
Instead, I should be getting an image somewhat similar to this:
The first part of the code - from "def deriv(z,t): to sol:odeint(deriv..." is where the values of x and y are generated, and using that I can then turn them into rectangular coordinates and graph them. How do I change my code to do this? I'm new to Python, so I might not understand some of the terminology. Thank you!
The first solution should give you the expected result, but there is a mistake in the implementation of the ode.
The function you pass to odeint should return an array containing the solutions of a 1st-order differential equations system.
In your case what you are solving is
While instead you should be solving
In order to do so change your code to this
import numpy as np
from scipy.integrate import odeint
from numpy import sin, cos, pi, array
import matplotlib.pyplot as plt
def deriv(z, t):
x, y, dxdt, dydt = z
dx2dt2 = (0.415 + x) * (dydt)**2 - 50 / 1.006 * x + 9.81 * cos(y)
dy2dt2 = (-9.81 * 1.006 * sin(y) - 2 * (dxdt) * (dydt)) / (0.415 + x)
return np.array([dxdt, dydt, dx2dt2, dy2dt2])
init = array([0, pi / 18, 0, 0])
time = np.linspace(0.0, 10.0, 1000)
sol = odeint(deriv, init, time)
plt.plot(sol[:, 0], sol[:, 1], label='hi')
plt.show()
The second part of the code looks like you are trying to do a change of coordinate.
I'm not sure why you try to solve the ode again instead of just doing this.
x = sol[:,0]
y = sol[:,1]
def plot(h):
x, y = h
n = (0.4 + x) * sin(y)
u = (0.4 + x) * cos(y)
return np.array([n, u])
n,u = plot( (x,y))
As of now, what you are doing there is solving this system:
Which leads to x=e^t and y=e^t and n' = (0.4 + e^t) * sin(e^t) u' = (0.4 + e^t) * cos(e^t).
Without going too much into the details, with some intuition you could see that this will lead to an attractor as the derivative of n and u will start to switch sign faster and with greater magnitude at an exponential rate, leading to n and u collapsing onto an attractor as shown by your plot.
If you are actually trying to solve another differential equation I would need to see it in order to help you further
This is what happen if you do the transformation and set the time to 1000:
I'm trying to acquire the bifurcation diagram for the equation below:
(x is a function of t)
as:
And here is my snippet:
import numpy as np
import matplotlib.pyplot as plt
def pitch(r, x):
return r * x + np.power(x,3)- np.power(x,5)
n = 10000
r = np.linspace(-200, 200, n)
iterations = 1000
last = 100
x = 0
for i in range(iterations):
x = pitch(r,x)
if i >= (iterations - last):
plt.plot(r,x, ',k', alpha=0.02)
plt.title("Bifurcation diagram")
plt.show()
But the generated plot is not what it is supposed to be:
Edit:
Here is my recent attempt:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def pitch(s,x,r):
x = s[0]
dxdt = r * x + np.power(x,3)- np.power(x,5)
return [dxdt]
t = np.linspace(0,100)
s0=[-50]
r = np.linspace(-200, 200)
for i in r:
s = odeint(pitch,s0,t, args=(i,))
plt.plot(s,i,',k', alpha=0.02)
plt.title("Bifurcation diagram")
plt.show()
With this error:
raise ValueError("x and y must have same first dimension") ValueError:
x and y must have same first dimension
Could you give me some advice to fix this problem?!
I found a link to this post and decided to post a few remarks that might be helpful to someone stumbling upon it in the future.
I did not analyze the equation in detail but it is clear from the first sight that something interesting would happen when r is close to 0.
So we could study the behavior of the system for r in [-10,10]
You are right to use odeint instead of solving the Cauchy problem using Euler method coded by yourself.
This equation has an attractor in that it soon "forgets" the initial condition and slides towards the attractor, yet the choice of the attractor depends on where in relation to 0 do we start. Large positive initial conditions would slide to the negative attractor and vice versa as - x^5 is the term that defines the behavior at large x.
What we need to do is for each r in the range put a mark at the attractor that the solution slides to for each initial condition.
We first create a canvas to put marks into:
diagram = np.zeros((200,200))
And then for each combination of (r,s0) we put a point on the canvas at (r,s[-1]).
Here is the complete code
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def pitch(s,x,r):
x = s[0]
dxdt = r * x + np.power(x,3)- np.power(x,5)
return [dxdt]
t = np.arange(0,100,2)
s0=[-50]
N = 200 # Number of points along each side of the diagram
diagram = np.zeros((N,N))
rmin,rmax = -10,10
rrange = np.arange(rmin, rmax,(rmax-rmin)/N)
smin,smax = -5.0,5.0
srange = np.arange(smin,smax,2*(smax-smin)/N)
for i in rrange:
for s0 in srange:
s = odeint(pitch,[s0],t, args=(i,))
imgx = int((i-rmin)*N/(rmax-rmin))
imgy = int((s[-1]-smin)/(smax-smin)*N)
imgx = min(N-1,max(0,imgx)) # make sure we stay
imgy = min(N-1,max(0,imgy)) # within the diagram bounds
diagram[imgy,imgx] = 1
plt.title("Bifurcation diagram")
plt.imshow(np.flipud(diagram),cmap=cm.Greys,
extent=[rmin,rmax,smin,smax],aspect=(rmax-rmin)/(smax-smin))
plt.xlabel("r")
plt.ylabel("x")
plt.show()
And the resulting plot
When you zoom in into the region around 0 by setting (rmin,rmax) to (-0.5,0.5) you could see that the branches of the diagram do not start at 0
Instead as in the diagram drawn in the original post the branches start at roughly r=-0.25