Solving nonlinear differential first order equations using Python - python

I would like to solve a nonlinear first order differential equation using Python.
For instance,
df/dt = f**4
I wrote the following program, but I have an issue with matplotlib, so I don't know if the method I used with scipy is correct.
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
derivate=lambda f,t: f**4
f0=10
t=np.linspace(0,2,100)
f_numeric=scipy.integrate.odeint(derivate,f0,t)
print(f_numeric)
plt.plot(t,f_numeric)
plt.show()
Which results in the following error:
AttributeError: 'float' object has no attribute 'rint'

In this case, you might be better of using Sympy, which allows you to obtain the closed form solutions:
from IPython.display import display
import sympy as sy
from sympy.solvers.ode import dsolve
import matplotlib.pyplot as plt
import numpy as np
sy.init_printing() # LaTeX like pretty printing for IPython
t = sy.symbols("t", real=True)
f = sy.symbols("f", function=True)
eq1 = sy.Eq(f(t).diff(t), f(t)**4) # the equation
sls = dsolve(eq1) # solvde ODE
# print solutions:
print("For ode")
display(eq1)
print("the solutions are:")
for s in sls:
display(s)
# plot solutions:
x = np.linspace(0, 2, 100)
fg, axx = plt.subplots(2, 1)
axx[0].set_title("Real part of solution of $\\frac{d}{dt}f(t)= (f(t))^4$")
axx[1].set_title("Imag. part of solution of $\\frac{d}{dt}f(t)= (f(t))^4$")
fg.suptitle("$C_1=0.1$")
for i, s in enumerate(sls, start=1):
fn1 = s.rhs.subs("C1", .1) # C_1 -> 1
fn2 = sy.lambdify(t, fn1, modules="numpy") # make numpy function
y = fn2(x+0j) # needs to be called with complex number
axx[0].plot(x, np.real(y), label="Sol. %d" % i)
axx[1].plot(x, np.imag(y), label="Sol. %d" % i)
for ax in axx:
ax.legend(loc="best")
ax.grid(True)
axx[0].set_ylabel("Re$\\{f(t)\\}$")
axx[1].set_ylabel("Im$\\{f(t)\\}$")
axx[-1].set_xlabel("$t$")
fg.canvas.draw()
plt.show()
In an IPython shell, you should see the following:

Related

Explicitly calculate convolution in Python

I want to calculate a convolution in Python by explicitly evaluating the integral
and comparing the result with what I get from fftconvolve. The integral would be calculated using quad:
import numpy as np
from scipy.integrate import quad
from scipy.signal import fftconvolve
import matplotlib.pyplot as plt
from sympy import symbols
def f(x,a,b):
return np.exp(-(x-a)**2/b)
def g(x,a,b):
return np.exp(-(x-np.pi*a)**2/(2.9*b))
x = symbols('x')
a = 1.2
b = 4.7
t = np.linspace(-100,100,int(1e4))
dt = t[1] - t[0]
h1 = fftconvolve(f(t,a,b),g(t,a,b),mode='same')*dt
h2,_ = quad(f(t,a,b)*g(x-t,a,b),-np.inf,np.inf,epsabs=0,epsrel=1e-6,args=(a,b))
x = np.linspace(-100,100,int(1e4))
plt.figure()
plt.plot(t,h1,label='fftconvolve')
plt.plot(x,h2,label='brute force')
plt.legend()
plt.show()
I keep getting the error AttributeError: 'Mul' object has no attribute 'exp' which refers to the line h2,_ = quad(... when it is called by quad.
What does this error mean and is this an appropriate way to use quad to evaluate the integral?

Plotting a symbolic function with multiple variables in Python

First code cell:
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
from ipywidgets.widgets import interact
sym.init_printing(use_latex="mathjax")
x, y, z, t = sym.symbols('x y z t')
I am required to plot the following function which I have defined as:
p_w = (1/sym.sqrt(sym.pi*(1-sym.exp(-2*t))))*sym.exp(-(z-sym.exp(-t))**2/(1-sym.exp(-2*t)))
Obviously t and z are both variables and I am to plot the function for t = 0.1,1, and 10, using z as my x-axis and p_w(z) as the y-axis.
I tried defining 3 functions j,k,l with the values subbed in for t like so:
j=p_w.evalf(subs={t:0.1})
k=p_w.evalf(subs={t:1})
l=p_w.evalf(subs={t:10})
then changing these to numpy arrays with the sym.lambdify() function:
j_np=sym.lambdify(z,j)
k_np=sym.lambdify(z,k)
l_np=sym.lambdify(z,l)
I defined my x-axis using:
myz = np.linspace(0,10,1000)
(The 1000 divisions was fairly arbitrary as I wasn't sure how many I'd need for an accurate graph)
Then I tried plotting just j to begin with as follows:
plt.plot(myz, j_np(myz))
and got the following error message:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-41-d743a8a00bcf> in <module>()
----> 1 plt.plot(myz,j_np(myz))
/anaconda3/lib/python3.6/site-packages/numpy/__init__.py in <lambda>. (_Dummy_164)
AttributeError: 'Mul' object has no attribute 'exp'
I am guessing the problem is that numpy does not understand 'exp' in the same way that sympy does, but I am unsure as to how to rectify it, or even if this is the problem at all. Any help would be much appreciated.
You can get this to work if you skip the evalf step:
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
from ipywidgets.widgets import interact
sym.init_printing(use_latex="mathjax")
# x, y, z, t = sym.symbols('x y z t')
from sympy.abc import x,y,z,t
p_w = (1/sym.sqrt(sym.pi*(1-sym.exp(-2*t))))*sym.exp(-(z - sym.exp(-t))**2/(1-sym.exp(-2*t)))
myz = np.linspace(0,10,1000)
lam=sym.lambdify((z,t), p_w)
myz = np.linspace(0,10,1000)
times = [.01, 1, 10]
for time in times:
plt.plot(myz, lam(myz, time))
Output:
It seems the underlying issue was that setting the time using p_w.evalf(subs={t:0.1}) doesn't really work:
print(p_w.evalf(subs={t:0.1}))
0.564189583547756*(1.0 - exp(-2*t))**(-0.5)*exp(-(z - exp(-t))**2/(1 - exp(-2*t)))
It works right if z is removed from p_w:
p_w = (1/sym.sqrt(sym.pi*(1-sym.exp(-2*t))))*sym.exp(-(- sym.exp(-t))**2/(1-sym.exp(-2*t)))
print(p_w.evalf(subs={t:0.1}))
0.0144778612224441
So apparently having the undetermined variable z in p_w prevents p_w.evalf from expanding the t terms correctly.

How to plot graphs from equations

I am trying to replicate some graphs from 3 equations.
My equation are shown in my python code below
The first two equations are plotted on the 1st graph
The first equation and the 3rd equation are plotted on the 2nd graph
The last two equations are plotted on the 3rd graph
My parameters are:
k1 = a range of values, k2=1, n1=3, n2=3, K1=0.3, K2=0.3, b1=0, b2=0.05
i'm unsure about how to plot this on a graph. any help would be great. thanks
note that i am a python beginner and have basic knowledge of coding
here's my code so far:
import numpy as np
import matplotlib.pyplot as plt
rateinact= k1*X
rateact12= k2*(b2*(K2**n2/(K2**n2 + X**n2)) + (X**n2/(K2**n2 + X**n2))*(1-X)
Rateinact2 = k1*(B1*((X**n1)/(K1**n1+X**n1))+((K1**n1)/(K1**n1+X**n1)))*(X)
#define parameters
k1 = []
k2=1
n1=3
n2=3
K1=0.3
K2=0.3
b1=0
b2=0.05
#graph 1
plt.plot(inact, 'r')
plt.plot(act12, 'b')
plt.ylabel('Rate of A inactivation or activation')
plt.xlabel('Fraction of activated A)
plt.show()
The trick you seem to be missing is how to make a range of values. This can be easily done with np.linspace since you're already using numpy.
x = np.linspace(0,1,100)
y = x**2 + 3*x + 4
plt.plot(x,y,'g-')
Or, for your specific example, with the syntax errors removed (I had to guess a little on what some values were):
-- EDIT --
I see now a little better what you wanted. Here's a quick demo of how you might accomplish this (I'm using subfigures instead of separate figures, but the idea is the same):
import numpy as np
import matplotlib.pyplot as plt
k1 = np.linspace(0,1,5)
k2=1
n1=3
n2=3
K1=0.3
K2=0.3
beta1=0
beta2=0.05
x = np.linspace(0,1)
def r_inact_1loop(x,k1=1):
return k1*x
def r_activation(x,k1=1):
return k2*(beta2*K2**n2/(K2**n2+x**n2) + x**n2/(K2**n2+x**n2))*(1-x)
def r_inact_2loop(x,k1=1):
return k1*(beta1*x**n1/(K1**n1+x**n1) + K1**n1/(K1**n1+x**n1))*x
#define parameters
#graph 1
fig = plt.figure(figsize=(16,8))
ax1 = fig.add_subplot(1,3,1)
ax2 = fig.add_subplot(1,3,2)
ax3 = fig.add_subplot(1,3,3)
ax1.set_xlabel('Fraction of activated A')
ax2.set_xlabel('Fraction of activated A')
ax3.set_xlabel('Fraction of activated A')
ax1.set_ylabel('Rate of A inactivation or activation')
ax2.set_ylabel('Rate of A inactivation or activation')
ax3.set_ylabel('Rate of A inactivation or activation')
for k in k1:
ax1.plot(x,r_inact_1loop(x,k),label='in1 k1={:.1f}'.format(k))
ax1.plot(x,r_activation(x,k),label='ac k1={:.1f}'.format(k))
ax1.legend(loc='best')
ax2.plot(x,r_inact_1loop(x,k),label='in1 k1={:.1f}'.format(k))
ax2.plot(x,r_inact_2loop(x,k),label='in2 k1={:.1f}'.format(k))
ax1.set_xlabel('Fraction of activated A')
ax2.legend(loc='best')
ax3.plot(x,r_activation(x,k),label='ac k1={:.1f}'.format(k))
ax3.plot(x,r_inact_2loop(x,k),label='in2 k1={:.1f}'.format(k))
ax3.legend(loc='best')
plt.show()
--ADDENDUM--
If you want the cool shading of the plots you were looking at, here's the code for that
ax2.fill_between(x,r_inact_1loop(x,k1[0]),r_inact_1loop(x,k1[-1]))
ax3.fill_between(x,r_inact_2loop(x,k1[0]),r_inact_2loop(x,k1[-1]))

Numpy roots function and pyplot plot

I want to plot the two solutions of quadratic equation as a function of a parameter ( function coeff(t) ). I am using function numpy.roots (I am sure that all roots are real in this case), and I am trying to invoke it from within pyplot.plot as below:
import numpy as np
import matplotlib.pyplot as plt
r = 3.74
def coeff(pp):
return np.array([pp-1,r+1-0.5*pp,-r])
def sroot(t):
return np.roots(coeff(t))
a = np.linspace(0,0.9,100)
fig = plt.figure()
plt.plot(a,sroot(a)[0,:])
plt.plot(a,sroot(a)[1,:])
plt.show()
I get error message:
File "quest.py", line 18, in <module>
plt.plot(a,sroot(a)[0,:])
File "quest.py", line 10, in sroot
return np.roots(coeff(t))
File "/usr/lib64/python2.7/site-packages/numpy/lib/polynomial.py", line 218, in roots
p = p.astype(float)
I understand that the numpy.roots takes only list of parameters and is unable to recognize a row in array 3xlen(a). Is there a way to do it in one line, preferably inside the pyplot.plot? I would like to avoid using loop.
This is because you transform all of your coefficient at once and try to call the numpy roots solver on all of them. np.roots only accept 1-d array and solves a single polynomial. Here is a script that does what you want:
import numpy as np
import matplotlib.pyplot as plt
# Parameters
r = 3.74
T = np.linspace(0.0,0.9,100)
# Coefficients
C = np.zeros((len(T),3))
C[:,0] = T-1
C[:,1] = r + 1 - 0.5*T
C[:,2] = r
# Roots
R = np.zeros((len(T),2))
for i in range(len(T)):
R[i] = np.roots(C[i])
# Plot
fig = plt.figure()
plt.plot(T,R[:,0])
plt.plot(T,R[:,1])
plt.show()

Solving a linear-quadratic system of equations, both graphically and numerically, in numpy/matplotlib?

I have a system of a linear equation and a quadratic equation that I can set up with numpy and scipy so I can get a graphical solution. Consider the example code:
#!/usr/bin/env python
# Python 2.7.1+
import numpy as np #
import matplotlib.pyplot as plt #
# d is a constant;
d=3
# h is variable; depends on x, which is also variable
# linear function:
# condition for h: d-2x=8h; returns h
def hcond(x):
return (d-2*x)/8.0
# quadratic function:
# condition for h: h^2+x^2=d*x ; returns h
def hquad(x):
return np.sqrt(d*x-x**2)
# x indices data
xi = np.arange(0,3,0.01)
# function values in respect to x indices data
hc = hcond(xi)
hq = hquad(xi)
fig = plt.figure()
sp = fig.add_subplot(111)
myplot = sp.plot(xi,hc)
myplot2 = sp.plot(xi,hq)
plt.show()
That code results with this plot:
It's clear that the two functions intersect, thus there is a solution.
How could I automatically solve what is the solution (the intersection point), while keeping most of the function definitions intact?
It turns out one can use scipy.optimize.fsolve to solve this, just need to be careful that the functions in the OP are defined in the y=f(x) format; while fsolve will need them in the f(x)-y=0 format. Here is the fixed code:
#!/usr/bin/env python
# Python 2.7.1+
import numpy as np #
import matplotlib.pyplot as plt #
import scipy
import scipy.optimize
# d is a constant;
d=3
# h is variable; depends on x, which is also variable
# linear function:
# condition for h: d-2x=8h; returns h
def hcond(x):
return (d-2*x)/8.0
# quadratic function:
# condition for h: h^2+x^2=d*x ; returns h
def hquad(x):
return np.sqrt(d*x-x**2)
# for optimize.fsolve;
# note, here the functions must be equal to 0;
# we defined h=(d-2x)/8 and h=sqrt(d*x-x^2);
# now we just rewrite in form (d-2x)/16-h=0 and sqrt(d*x-x^2)-h=0;
# thus, below x[0] is (guess for) x, and x[1] is (guess for) h!
def twofuncs(x):
y = [ hcond(x[0])-x[1], hquad(x[0])-x[1] ]
return y
# x indices data
xi = np.arange(0,3,0.01)
# function values in respect to x indices data
hc = hcond(xi)
hq = hquad(xi)
fig = plt.figure()
sp = fig.add_subplot(111)
myplot = sp.plot(xi,hc)
myplot2 = sp.plot(xi,hq)
# start from x=0 as guess for both functions
xsolv = scipy.optimize.fsolve(twofuncs, [0, 0])
print(xsolv)
print("xsolv: {0}\n".format(xsolv))
# plot solution with red marker 'o'
myplot3 = sp.plot(xsolv[0],xsolv[1],'ro')
plt.show()
exit
... which results with:
xsolv: [ 0.04478625 0.36380344]
... or, on the plot image:
Refs:
Roots finding, Numerical integrations and differential equations - Scipy: Scientific Programming in Python
Is there a python module to solve linear equations? - Stack Overflow

Categories

Resources