ODE of Second order in python - python

import sympy as sym
sym.init_printing()
import scipy as sp
import matplotlib as mpl
import matplotlib.pyplot as plt
#%%
x = sym.symbols('x')
f, g = sym.symbols('f g', cls=sym.int)
# f''+ 30000*f'+ 100000000*f = 0.001
# f(0) = 0 e f'(0) = 0
diffeq = sym.Eq(f(x).diff(x, x) + (30000)*f(x).diff(x) + (100000000)*f(x), sym.(0.001))
soln = sym.dsolve(diffeq,f(x))
constants = sym.solve([soln.rhs.subs(x,0) - 0, soln.rhs.diff(x,1).subs(x,0)- 0])
C1, C2 = sym.symbols('C1,C2')
soln = soln.subs(constants)
func = sym.lambdify(x,soln.rhs,'numpy')
#%%
#ploting the solution f(x)
xx = sp.arange(-1,1,.01)
y = func(xx)
plt.figure(1)
plt.plot(xx,y);
Hi! I want to solve this ODE of second order in python but it seems I'm doing something wrong.
f'' means the second derivate of f(x)
f' means the first derivate of f(x)

Related

How to do a (trapeze) integration in Python with x^2?

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.

Sympy gives a discontinuous solution to a simple ODE involving Piecewise

I am trying to solve a linear ODE with a rectangular signal as second member, for the first and second order :
I define the second member with sympy.Piecewise. For The first order, Sympy gives the expecting result. But for the second order, the result is discontinuous. Sympy seems not to take y(5) as initial condition for the t>5 part.
How could I have a continuous solution ?
Here is my code :
python
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp
t = sp.symbols('t')
y = sp.Function('y')
f = sp.Function('f')
#%% First order
t = sp.symbols('t')
y = sp.Function('y')
f = sp.Piecewise((1, t<5), (0, True))
eq = sp.Eq(y(t).diff(t) + y(t), f)
ics = {y(0): 0}
sol = sp.dsolve(eq, ics=ics)
# plot
yl = sp.lambdify(t, sol.rhs, modules='numpy')
fl = sp.lambdify(t, f, modules='numpy')
t_val = np.linspace(0,10,500)
plt.figure()
plt.plot(t_val, yl(t_val), label='y(t)')
plt.plot(t_val, fl(t_val), label='f(t)')
plt.title('first order', fontsize=30)
plt.legend(fontsize=20)
#%% Second order
t = sp.symbols('t')
y = sp.Function('y')
f = sp.Piecewise((1, t<5), (0, True))
eq = sp.Eq(sp.diff(y(t),t,t) + y(t) + sp.diff(y(t),t), f)
ics = {sp.diff(y(t),t).subs(t, 0): 0, y(0): 0}
sol = sp.dsolve(eq, ics=ics)
# plot
yl = sp.lambdify(t, sol.rhs, modules='numpy')
fl = sp.lambdify(t, f, modules='numpy')
t_val = np.linspace(0,10,500)
plt.figure()
plt.plot(t_val, yl(t_val), label='y(t)')
plt.plot(t_val, fl(t_val), label='f(t)')
plt.title('Second order', fontsize=30)
plt.legend(fontsize=20)

Plotting mathematical function in python

i'm trying to write function called plotting which takes i/p parameters Z, p and q and plots the function
f(y) = det(Z − yI) on the interval [p, q]
(Note: I is the identity matrix.) det() is the determinant.
For finding det(), numpy.linalg.det() can be used
and for indentity matrix , np.matlib.identity(n)
Is there a way to write such functions in python? and plot them?
import numpy as np
def f(y):
I2 = np.matlib.identity(y)
x = Z-yI2
numpy.linalg.det(x)
....
Is what i am tryin correct? any alternative?
You could use the following implementation.
import numpy as np
import matplotlib.pyplot as plt
def f(y, Z):
n, m = Z.shape
assert(n==m)
I = np.identity(n)
x = Z-y*I
return np.linalg.det(x)
Z = np.matrix('1 2; 3 4')
p = -15
q = 15
y = np.linspace(p, q)
w = np.zeros(y.shape)
for i in range(len(y)):
w[i] = f(y[i], Z)
plt.plot(y, w)
plt.show()

Plotting multiple subplots on same graph

from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import math
from scipy.integrate import odeint
from scipy.fftpack import fft, ifft
def pend(y, t, a, b, ohm):
theta, omega, phi = y
dydt = [omega, -b*omega-np.sin(theta)-a*np.cos(phi), ohm]
return dydt
b = 1.0/2.0 #beta
ohm = 2.0/3.0 #capital Omega
period = 2.0*math.pi/ohm #driving period
t0 = 0.0 #initial time
t = np.linspace(t0,t0+period*10**3,10**3+1) #time for Poincare map
theta0 = 0.75
omega0 = 1.6
phi0 = 0.8
y0 = [theta0,omega0,phi0] #initial conditions
N = 100 #number of transient points to delete
a_array = np.linspace(0,1.15,50) #varying parameter of a values
for a in a_array:
sol = odeint(pend,y0,t,args=(a,b,ohm)) #numerical integration of differential equation
sol = sol[N:10**3-N] #removing transients
w = sol[:,1] #frequency
A = np.full(len(w),a) #array of a-values
plt.plot(A, w)
plt.draw()
I'm trying to construct a bifurcation diagram currently. In the system of equations we're using, a is the control parameter, which we're plotting for values between 0 and 1.15 on the x-axis vs. an array of values (called w) for a particular value of a. I'm not really sure how to plot things from within a for loop like this. I've heard that subplots are the best way to go, but I'm unfamiliar with implementation and could use some help. Thanks!
Unindenting the last command worked for me.
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import math
from scipy.integrate import odeint
from scipy.fftpack import fft, ifft
def pend(y, t, a, b, ohm):
theta, omega, phi = y
dydt = [omega, -b*omega-np.sin(theta)-a*np.cos(phi), ohm]
return dydt
b = 1.0/2.0 #beta
ohm = 2.0/3.0 #capital Omega
period = 2.0*math.pi/ohm #driving period
t0 = 0.0 #initial time
t = np.linspace(t0,t0+period*10**3,10**3+1) #time for Poincare map
theta0 = 0.75
omega0 = 1.6
phi0 = 0.8
y0 = [theta0,omega0,phi0] #initial conditions
N = 100 #number of transient points to delete
a_array = np.linspace(0,1.15,50) #varying parameter of a values
for a in a_array:
sol = odeint(pend,y0,t,args=(a,b,ohm)) #numerical integration of differential equation
sol = sol[N:10**3-N] #removing transients
w = sol[:,1] #frequency
A = np.full(len(w),a) #array of a-values
plt.plot(A, w)
plt.show()

Plotting Sympy Result to Particular Solution of Differential Equation

So far I have managed to find the particular solution to this equation for any given mass and drag coefficient. I have not however found a way to plot the solution or even evaluate the solution for a specific point. I really want to find a way to plot the solution.
from sympy import *
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f = Function('f')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t:0}),C1)[0]
equation = equation.subs({C1:C1_ic})
For completeness, you may also use Sympy's plot, which is probably more convenient if you want a "quick and dirty" plot.
plot(equation.rhs,(t,0,10))
Import these libraries (seaborn just makes the plots pretty).
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
Then tack this onto the end. This will plot time, t, against velocity, v(t).
# make a numpy-ready function from the sympy results
func = lambdify(t, equation.rhs,'numpy')
xvals = np.arange(0,10,.1)
yvals = func(xvals)
# make figure
fig, ax = plt.subplots(1,1,subplot_kw=dict(aspect='equal'))
ax.plot(xvals, yvals)
ax.set_xlabel('t')
ax.set_ylabel('v(t)')
plt.show()
I get a plot like this for a mass of 2 and a drag coefficient of 2.
If I've understood correctly, you want to represent the right hand side of your solution, here's one of the multiple ways to do it:
from sympy import *
import numpy as np
import matplotlib.pyplot as plt
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f = Function('f')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t: 0}), C1)[0]
equation = equation.subs({C1: C1_ic})
t1 = np.arange(0.0, 50.0, 0.1)
y1 = [equation.subs({t: tt}).rhs for tt in t1]
plt.figure(1)
plt.plot(t1, y1)
plt.show()

Categories