Boundaries condition using ```solve_ivp``` - python

I am trying to solve a differential system equation using solve_ivp from scipy.integrate, but what I have readen in the web https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html
is when the boundaries conditions are given in the initial point t=t_0. I Would like to know how to modify it, to be more precise, I would like to solve the next problem
the coefficients are constants, and the U_i's only depent of x, L>0, and in this case I don't know how to specify these kind of boundary conditions, what I have done
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
# Coefficients of matrix
u1=2
u2=2
k12=3
k13=2
k14=10
k21=6
k23=27
k24=13
k31=2
k32=15
k34=31
k41=37
k42=10
k43=1j
zeta1=1
zeta2=1
nu=1 # Nu parameter
# Boundaries condition
L=10
interval=[-L/2,L/2]
boundaries_conditions=[0,0,0,0]
### Definition of matrix of coeficients
Matrix_A=np.array([[-u1, k12, k13,k14],
[k21, u1, k23, k24],
[k31, k32, -u2, k34],
[k41, k42, k43, u2]])*1j
# Definition of the homogeneous system
def hom_system(x , U, u_1, u_2, u_3, u_4):
U1, U2, U3, U4 = U,U,U,U
line1=np.dot(Matrix_A[0],np.array([U1,U2,U3,U4]))
line2=np.dot(Matrix_A[1],np.array([U1,U2,U3,U4]))
line3=np.dot(Matrix_A[2],np.array([U1,U2,U3,U4]))
line4=np.dot(Matrix_A[3],np.array([U1,U2,U3,U4]))
return [line1,line2,line3,line4]
If someone could give some hints I would appreciate very much, thanks.

Related

least square method for finding unknown variables

I need to compute two unknown variable with least square method , I have got the experimental data which are produced ( simiulated ) by a few line of code at first. so at the beginning two variable which are phase and width are known to simulate the data. in the second part these two variable are considered unknown and with the help of data and least squares method I am going to compute them. but there is a problem!. if the phase is between 0 to pi the code gives the right value and when it is between pi to 2*pi wrong value is retuned. I need to compute these two variables for any arbitrary value with high precision that is entered in the first part.
Thanks to those who would help in advance.
this is the code bellow:
from numpy import sin,cos,pi,linspace,sqrt,zeros,arccos
from scipy.special import fresnel as f
import matplotlib.pyplot as plt
from scipy.optimize import least_squares as lst
import numpy as np
# first part to simulate data
m=500
l=632.8e-9
z=.25
a=0.3e-3
b=6e-3
p=(1.7)*pi
q=sqrt(2/(l*z))
x=linspace(-b,b,m)
v2=-q*(x-a)
v1=-q*(x+a)
s,c,I=zeros(m),zeros(m),zeros(m)
for i in range(m):
s[i]=f(v2[i])[0]-f(v1[i])[0]
c[i]=f(v2[i])[1]-f(v1[i])[1]
for j in range(m):
I[j]=1+(1-cos(p))*((c[j]**2 +s[j]**2 )-(c[j]+s[j]))+sin(p)*(c[j]-s[j])
# second part to compute a and p
def model(y,x):
w=sqrt(2/(l*z))
C=f(w*(y[1]-x))[1]-f(w*(-y[1]-x))[1]
S=f(w*(y[1]-x))[0]-f(w*(-y[1]-x))[0]
return 1+(1-cos(y[0])) *(C**2 -C +S**2 -S)+sin(y[0])*(C-S)
def func(y,x,z):
return (z-model(y,x))
ExI=I
y0=np.array([0.5,50e-6])
reslm = lst(func, y0,method='lm',args=(x, ExI),verbose=2)
print('Real phase and channel width : ',p , a)
print(' lm method ')
print('Estimated phase : ' ,reslm.x[0] if reslm.x[0]>=0 else 2*pi+reslm.x[0])
print('channel width' , reslm.x[1])

Scipy solve_ivp not giving expected solutions

I need to solve a 2nd order ODE which I have decoupled into two first order ODEs. I've tried solving it using solve_ivp, but it doesn't seem to provide the solution I expect. I have provided the code below.
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative
from scipy.integrate import solve_ivp
from matplotlib import rc
rc('text', usetex = True)
V0 = 2*10**-10
A = 0.130383
f = 0.129576
phi_i_USR2 = 6.1
phi_Ni_USR2 = 1.2
def V_USR2(phi):
return V0*(np.tanh(phi/np.sqrt(6)) + A*np.sin(1/f*np.tanh(phi/np.sqrt(6))))**2
def V_phi_USR2(phi):
return derivative(V_USR2, phi)
N = np.linspace(0,66,1000)
def USR2(N, X):
phi, g = X
return [g, (g**2/2 - 3)*(V_phi_USR2(phi)/V_USR2(phi) + g)]
X0 = [phi_i_USR2, phi_Ni_USR2]
sol = solve_ivp(USR2, (0,66), X0, method = 'LSODA', t_eval = N)
phi_USR2 = sol.y[0]
phi_N_USR2 = sol.y[1]
N_USR2 = sol.t
plt.plot(phi_USR2, phi_N_USR2)
plt.xlabel("$\phi$")
plt.ylabel("$\phi'$")
plt.title("Phase plot for USR2")
plt.show()
solve_ivp gives me the following plot:
The problem is that there is supposed to be an oscillation near the origin, which is not well captured by solve_ivp. However, for the same equation and initial conditions, Mathematica gives me exactly what I want:
I want the same plot in Python as well. I tried various methods in solve_ivp such as RK45, LSODA, Radau and BDF, but all of them show the same problem (LSODA tries to depict an oscillation but fails, but the other methods don't even move past the point where the oscillation starts). It would be great if someone can shed light on the problem. Thanks in advance.

How can I modify this differential equation solver to solve for a large number of variables?

I would like to modify the following code so that it can solve for thousands of variables with thousands of couple differential equations. The problem is that I would like to be able to import the variable list (y), ideally as a numpy array, but acceptably as a regular list. The list will be massive, so I don't want to define it in the function. If I do something like define a='n','c1',... and then set a=y, python complains that the variables are the wrong type. If I define a= n, c1,....python complains that I haven't defined the variables. If you have any advice on how to import the very large variable list for this function as a list or numpy array that would be great.
import numpy as np
from scipy.integrate import odeint
def kinetics(y,t,b1,b2):
n,c1=y
dydt=[(b1*n)+(b2*c1),(b1*n)-(c1)]
return dydt
b1=0.00662888
b2=0.000239997
n0=1
c1_0=1
y0=[n0,c1_0]
t = np.linspace(0, 10, 10)
sol = odeint(kinetics, y0, t, args=(b1,b2))
print(sol)
This sort of renaming and use of individual python objects for each step is likely to be slow, especially if you can use numpy array vectorization for parts of the computation. Note that your current code can be reformulated into a linear algebra problem which could be solved very efficiently using numpy, assuming this is true for the rest of the ODE structure. I warn against the path you want to take.
But, assuming that nothing can be vectorized in this way, and you want to continue down this path, you could define a class to store all your data and create an instance of said class with the current state of y at each function call. You could store the class definition in a separate python module to keep the problem definition tidy if needed.
If using python 3:
import numpy as np
from scipy.integrate import odeint
class vars:
def __init__(self, *args):
(self.n, self.c1) = args
def kinetics(y,t,b1,b2):
v = vars(*y)
dydt=[
(b1 * v.n) + (b2 * v.c1),
(b1 * v.n) - (v.c1)
]
return dydt
b1=0.00662888
b2=0.000239997
n0=1
c1_0=1
y0=[n0,c1_0]
t = np.linspace(0, 10, 10)
sol = odeint(kinetics, y0, t, args=(b1,b2))
print(sol)

Plotting 2D integral function in python

Here is my first steps within the NumPy world.
As a matter of fact the target is plotting below 2-D function as a 3-D mesh:
N = \frac{n}{2\sigma\sqrt{\pi}}\exp^{-\frac{n^{2}x^{2}}{4\sigma^{2}}}
That could been done as a piece a cake in Matlab with below snippet:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
mu = 0;
sigma = sqrt(2)./n;
f = normcdf(x,mu,sigma);
mesh(x,n,f);
But the bloody result is ugly enough to drive me trying Python capabilities to generate scientific plots.
I searched something and found that the primary steps to hit above mark in Pyhton might be acquired by below snippet:
from matplotlib.patches import Polygon
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
sigma = 1
def integrand(x,n):
return (n/(2*sigma*np.sqrt(np.pi)))*np.exp(-(n**2*x**2)/(4*sigma**2))
t = np.linespace(0, 20, 0.01)
n = np.linespace(1, 100, 1)
lower_bound = -100000000000000000000 #-inf
upper_bound = t
tt, nn = np.meshgrid(t,n)
real_integral = quad(integrand(tt,nn), lower_bound, upper_bound)
Axes3D.plot_trisurf(real_integral, tt,nn)
Edit: With due attention to more investigations on Greg's advices, above code is the most updated snippet.
Here is the generated exception:
RuntimeError: infinity comparisons don't work for you
It is seemingly referring to the quad call...
Would you please helping me to handle this integrating-plotting problem?!...
Best
Just a few hints to get you in the right direction.
numpy.meshgrid can do the same as MatLABs function:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html
When you have x and n you can do math just like in matlab:
sigma = numpy.sqrt(2)/n
(in python multiplication/division is default index by index - no dot needed)
scipy has a lot more advanced functions, see for example How to calculate cumulative normal distribution in Python for a 1D case.
For plotting you can use matplotlibs pcolormesh:
import matplotlib.pyplot as plt
plt.pcolormesh(x,n,real_integral)
Hope this helps until someone can give you a more detailed answer.

Solving nonlinear overdetermined system using python

I'm trying to find a good way to solve a nonlinear overdetermined system with python. I looked into optimization tools here http://docs.scipy.org/doc/scipy/reference/optimize.nonlin.html but I can't figure out how to use them. What I have so far is
#overdetermined nonlinear system that I'll be using
'''
a = cos(x)*cos(y)
b = cos(x)*sin(y)
c = -sin(y)
d = sin(z)*sin(y)*sin(x) + cos(z)*cos(y)
e = cos(x)*sin(z)
f = cos(z)*sin(x)*cos(z) + sin(z)*sin(x)
g = cos(z)*sin(x)*sin(y) - sin(z)*cos(y)
h = cos(x)*cos(z)
a-h will be random int values in the range 0-10 inclusive
'''
import math
from random import randint
import scipy.optimize
def system(p):
x, y, z = p
return(math.cos(x)*math.cos(y)-randint(0,10),
math.cos(x)*math.sin(y)-randint(0,10),
-math.sin(y)-randint(0,10),
math.sin(z)*math.sin(y)*math.sin(x)+math.cos(z)*math.cos(y)-randint(0,10),
math.cos(x)*math.sin(z)-randint(0,10),
math.cos(z)*math.sin(x)*math.cos(z)+math.sin(z)*math.sin(x)-randint(0,10),
math.cos(z)*math.sin(x)*math.sin(y)-math.sin(z)*math.cos(y)-randint(0,10),
math.cos(x)*math.cos(z)-randint(0,10))
x = scipy.optimize.broyden1(system, [1,1,1], f_tol=1e-14)
could you help me out a bit here?
If I understand you right, you want to find an approximate solution to the non-linear system of equations f(x) = b where b is the vector containing the random values b=[a,...,h].
In order to do this you will first need to remove the random values from the system function, because otherwise in each iteration the solver will try to solve a different equation system. Moreover, I think that the basic Broyden method only works for a system with as many unknowns as equations. Alternatively you could use scipy.optimize.leastsq. A possible solution looks like this:
# I am using numpy because it's more convenient for the generation of
# random numbers.
import numpy as np
from numpy.random import randint
import scipy.optimize
# Removed random right-hand side values and changed nomenclature a bit.
def f(x):
x1, x2, x3 = x
return np.asarray((math.cos(x1)*math.cos(x2),
math.cos(x1)*math.sin(x2),
-math.sin(x2),
math.sin(x3)*math.sin(x2)*math.sin(x1)+math.cos(x3)*math.cos(x2),
math.cos(x1)*math.sin(x3),
math.cos(x3)*math.sin(x1)*math.cos(x3)+math.sin(x3)*math.sin(x1),
math.cos(x3)*math.sin(x1)*math.sin(x2)-math.sin(x3)*math.cos(x2),
math.cos(x1)*math.cos(x3)))
# The second parameter is used to set the solution vector using the args
# argument of leastsq.
def system(x,b):
return (f(x)-b)
b = randint(0, 10, size=8)
x = scipy.optimize.leastsq(system, np.asarray((1,1,1)), args=b)[0]
I hope this is of help for you. However, note that it is extremely unlikely that you will find a solution, especially when you generate random integers in the interval [0,10] while the range of f is limited to [-2,2]

Categories