I am trying to use sympy to solve an equation for a one dimensional steady state model of the solar wind. I have the code below
from sympy import Eq, var, solve
var('r',real=True)
eq = Eq((1./2.)*((CF**2)/(r))+CT*r**(gamma)+bm/(2.*muo) - CM)
a = solve(eq,r)
Where CF, CT, CM, gamma, muo, and bm are just real numbers. I am trying to solve the equation for r over a range of values for bm but it will not return any numbers. Upon running the block of code, my python notebook just displays that the code is running but doesnt return a value nor does it stop. Is there an alternative function or some sort of command I should be giving to sympy in order to make it work faster?
The equation involves the sum of two powers of r, including r**gamma. Unless gamma is a very small integer (between -4 and 4), there is no hope of solving this symbolically (which is what sympy is for).
To solve it numerically, you need scipy rather than sympy. For example:
from scipy.optimize import fsolve
func = lambda r : (1./2.)*((CF**2)/(r))+CT*r**(gamma)+bm/(2.*muo) - CM
# assign some numeric values to CF, CT, gamma, bm, muo, CM
sol = fsolve(func, 1) # 1 is the initial guess for the solver
Related
I have solved a single second order differential equation with two boundary conditions using the module solve_bvp. However, now I am trying to solve the system of two second order differential equations;
U'' + a*B' = 0
B'' + b*U' = 0
with the boundary conditions U(+/-0.5) = +/-0.01 and B(+/-0.5) = 0. I have split this into a system of first ordinary differential equations and I am trying to use solve_bvp to solve them numerically. However, I am just getting arrays full of zeros for my solution. I believe I am implementing the boundary conditions wrong. It is not clear to me how to handle more than two equations from the documentation. My attempt is below
import numpy as np
from scipy.integrate import solve_bvp
import matplotlib.pyplot as plt
%matplotlib inline
from scipy.integrate import solve_bvp
alpha = 1E-8
zeta = 8E-3
C_k = 0.05
sigma = 0.01
def fun(x, y):
return np.vstack((y[1],-((alpha)/(C_k*sigma))*y[2],y[2], -(1/(C_k*zeta))*y[1]))
def bc(ya, yb):
return np.array([ya[0]+0.001, yb[0]-0.001,ya[0]-0, yb[0]-0])
x = np.linspace(-0.5, 0.5, 5000)
y = np.zeros((4, x.size))
print(y)
sol = solve_bvp(fun, bc, x, y)
print(sol)
In my question I have just relabeled a and b, but they're just parameters that I input. I have the analytic solution for this set of equations so I know one exists that is non-trivial. Any help would be greatly appreciated.
It is most times really helpful if you state at least once in a comment or by assignment to specifically named variables how you want to compose the state vector.
By the form of the derivative return vector, I would think you intend
U, U', B, B'
which means that U=y[0], U'=y[1] and B=y[2],B'=y[3], so that your derivatives vector should correctly be
return y[1], -((alpha)/(C_k*sigma))*y[3], y[3], -(1/(C_k*zeta))*y[1]
and the boundary conditions
return ya[0]+0.001, yb[0]-0.001, ya[2]-0, yb[2]-0
Especially your boundary condition should throw the algorithm in the first step because of a singular Jacobian, always check the .success field and the .message field of the solution structure.
Note that by default the absolute and relative tolerance of the experimental solve_bvp is 1e-3, and the number of nodes is limited to 500.
Setting the initial node number to 50 (5000 is much too much, the solver refines where necessary), and the tolerance to 1-6, I get the following solution plots that visibly satisfy the boundary conditions.
I would like to solve the following formulas numerically in Python;
In Mathematica, you can input multiple differential equations and solve it at the same time. Is there a way to do the similar thing with Scipy?
edit: yes, I have looked at scipy.integrate.odeint already, but I'm still not sure how I can solve multiple equations that correlates each other at the same time. Does anyone have suggestion for that?
Eventually I figured out myself and I'm writing down for other people who might be clueless like me;
in odeint, you give three parameters model, y, and t where model is a function that takes in y and t then return dydt, y is the initial value of y, and t is the variable you're trying to take integral over. If you have multiple differential equations that are dependent on each other, you can just pass in all of them to odeint. In my case,
t = np.linspace(0, 20) # range of t
y0 = [No_0, Na_0, Ni_0, Nn_0] # initial condition for each Ns
def model(y, t):
No, Na, Ni, Nn = y
dNodt = -k_oa * No
dNadt = k_oa * No - k_ai * Na
dNidt = k_ai * Na - k_in * Ni
dNndt = k_in * Ni
return [dNodt, dNadt, dNidt, dNndt]
y = odeint(model, y0, t)
You can define multiple differential equations you want to solve within the model you define, and pass in to odeint along with the initial values for all species.
Have a loot at SciPy's Integration package:
https://docs.scipy.org/doc/scipy/reference/integrate.html
specifically at odeint to solve systems of ODE's:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.odeint.html#scipy.integrate.odeint
So I have this complicated equation which I need to solve. I think that finally x should be of order 1E22. But the problem with this code is that it crashes my entire system. Is there a fix? I tried scipy.optimize.root but it doesn't really solve anything at this order of magnitude (it gives final answer as initial guess without any iteration).
from scipy.optimize import fsolve
import math
import mpmath
import scipy
import sympy
from sympy.solvers import solve
from sympy import Symbol
from sympy import sqrt,exp
x = Symbol('x',positive=True)
cs = 507.643E-12
esi = 1.05E-10
q = 1.6E-19
T = 300
k = 1.381E-23
ni = 1.45E16
print(solve(exp(x/((2*cs/(esi*q))**2)) - ((x/ni)**(esi*k*T)),x))
def func(N):
return (math.exp(N/math.pow(2*cs/(esi*q),2)) - math.pow(N/ni,(esi*k*T)))
n_initial_guess = 1E21
n_solution = fsolve(func, n_initial_guess)
print ("The solution is n = %f" % n_solution)
print ("at which the value of the expression is %f" % func(n_solution))
print(scipy.optimize.root(func, 1E22,tol=1E-10))
Neither of the scipy functions work. The sympy function crashes my laptop. Would Matlab be ideal for this?
Numeric solution with SciPy
The problem that SciPy has with this equation is the loss of significance. You are raising N to the tiny power esi*k*T which makes it very near 1; in floating point arithmetics, it becomes exactly 1. Similarly, the part coming from the exponential becomes 1. Then the two parts are subtracting, leaving 0 - equation appears to be already solved. You could have seen this happening by printing func(1E21) -- it returns 0.
The way to deal with the loss of significance is to rewrite the equation, from the original form
exp(x/((2*cs/(esi*q))**2)) == (x/ni)**(esi*k*T)
by raising both sides to the power 1/(esi*k*T):
exp(x*esi*q**2/(2*cs*k*T)**2)) == x/ni
So func becomes
def func(N):
return np.exp(N*esi*q**2/(k*T*(2*cs)**2)) - (N/ni)
(It's is advisable to use NumPy functions with SciPy solvers.) That said, the solvers, for example root(func, 1E10), will report being unable to converge to a solution.
Symbolic solution with SymPy
SymPy is for solving equations analytically. It does not care for a bunch of floating point numbers. Give it a symbolic equation instead:
x, a, b, c = symbols('x, a, b, c', positive=True)
sol = solve(exp(x/a) - (x/b)**c, x)[0]
The solution is obtained as -c*LambertW(-a/(b*c))/a. Then it can be evaluated:
cs = 507.643E-12
esi = 1.05E-10
q = 1.6E-19
T = 300
k = 1.381E-23
ni = 1.45E16
print(sol.evalf(subs={a: (2*cs/(esi*q))**2, b: ni, c: esi*k*T}))
Which prints -21301663061.0653 - 4649834682.69762*I confirming what one would already expect from the failure of convergence with SciPy: there are no real solutions of the equation.
I am working on simulation of a system that contains coupled differential equations. My main aim is to solve the mass balance in steady condition and feed the solution of steady state as initial guess for the dynamic simulation.
There are basically three state variables Ss,Xs and Xbh. The rate equations look like this:
r1=µH(Ss/(Ks+Ss))(So/(Koh+So))Xbh+Kh(
(Xs⁄Xbh)/(Xs⁄Xbh+Kx))(So/(Koh+So))Xbh
r2=(1-fp)bH*Xbh-Kh( (Xs⁄Xbh)/(Xs⁄Xbh+Kx))(So/(Koh+So))Xbh
r3=µH(Ss/(Ks+Ss))(So/(Koh+So))Xbh-bH*Xbh
And the main differential equations derived from mole balance for CSTR are:
dSs/dt = Q(Ss_in-Ss)+r1*V
dXs/dt= Q(Xs_in-Xs)+r2*V
dXbh/dt= Q(Xbh_in-Xbh)+r2*V
Here is my code till now:
import numpy as np
from scipy.optimize import fsolve
parameter=dict()
parameter['u_h']=6.0
parameter['k_oh']=0.20
parameter['k_s']=20.0
parameter['k_h']=3.0
parameter['k_x']=0.03
parameter['Y_h']=0.67
parameter['f_p']=0.08
parameter['b_h']=0.62
Bulk_DO=2.0 #mg/L
#influent components:
infcomp=[56.53,182.9,16.625] #mgCOD/l
Q=684000 #L/hr
V=1040000 #l
def steady(z,*args):
Ss=z[0]
Xs=z[1]
Xbh=z[2]
def monod(My_S,My_K):
return My_S/(My_S+My_K)
#Conversion rates
#Conversion of Ss
r1=((-1/parameter['Y_h'])*parameter['u_h']*monod(Ss,parameter['k_s'])\
+parameter['k_h']*monod(Xs/Xbh,parameter['k_x'])*monod(Bulk_DO,parameter['k_oh']))\
*Xbh*monod(Bulk_DO,parameter['k_oh'])
#Conversion of Xs
r2=((1-parameter['f_p'])*parameter['b_h']-parameter['k_h']*monod(Xs/Xbh,parameter['k_x']))*Xbh
#Conversion of Xbh
r3=(parameter['u_h']*monod(Ss,parameter['k_s'])*monod(Bulk_DO,parameter['k_oh'])-parameter['b_h'])*Xbh
f=np.zeros(3)
f[0]=Q*(infcomp[0]-Ss)+r1*V
f[1]=Q*(infcomp[1]-Xs)+r2*V
f[2]=Q*(infcomp[2]-Xbh)+r3*V
return f
initial_guess=(0.1,0.1,0.1)
soln=fsolve(steady,initial_guess,args=parameter)
print (soln)
How can I plot steady condition like this?
steady state plot
The solution is also not what I want since the equations implies reduction in Ss and Xs and increase of Xbh values with time. Also one solution has negative value which is practically impossible.
Any suggestions would be highly appreciated. Thanks in advance !!
This is a solution to getting negative values for your solution: instead of using fsolve, use least_squares, which allows you to set bounds to the possible values.
In the top, import:
from scipy.optimize import least_squares
And replace the fsolve statement with:
soln = least_squares(steady, initial_guess, bounds=[(0,0,0),(np.inf,np.inf,np.inf)], args=parameter)
So, I'm trying to write a code that solves the (what we called) differential equation of an orbit in the kepler potential V(r)=-1/r
when you do the math you get a differential equation that looks like this:
d^2u/d(fi)^2 + u - m/M^2=0
where u=1/r
and we are ultimately looking for r(fi)
and now i tried to solve it using the numerical method, first i said du/dfi=y
then definig a function (i took some arbitrary M and m)
def func(y,fi):
m=4
M=5
return [y[1],m/M^2-y[0]]$
and imported from scipy.integrate import odeint
and then put in
ts = np.linspace(0,15,150)
ys = odeint(func, y0, ts)
now this gets me an array of 150 arrays of two numbers
and i don't really understand what dodes the first number mean and what does the second number mean is is
ys=[fi,u(fi)]
or something else?
The state for your order one system is [value, derivative]. The result of the integration is a list of state pairs of the same type.