Error in my Scipy Code for Blood Glucose Model - python

When I run my code I get some sort of error and I don't know why.
line 233, in odeint
int(bool(tfirst)))
RuntimeError: The size of the array returned by func (3) does not match the size of y0 (4).
from scipy.integrate import odeint
# define a function containing the derivatives, i.e. the ODE
def glucose(x,t,params):
X,I, G, Y = x
k, alpha, beta, gamma_X, gamma_I, gamma_G, lamda, delta = params
derivs = [k - gamma_X * X - beta * I * X + lamda * G * Y,
alpha * X - gamma_I * I,
delta * Y - gamma_X * G]
return derivs
k = 5.625 #set value
alpha = 1.111 #the rate of insulin production
delta= 1 #the rate of glucagon production
beta = 0.2 #glycogen produced based on insulin
lamda= 0.1 #glucose produced based on glycogen
gamma_X = 0.25 #glucose used
gamma_I = 1.0 #insulin turnover
gamma_G= 0.5 #glucagon turnover
params = [k, alpha, beta, gamma_X, gamma_I, delta, gamma_G, lamda]
X = 6
I = 5
G= 4 #Glucagon
Y= 5 #Glycagon
x0 = [X,I,G,Y]
maxt = 12.0
tstep = 0.05
t = np.arange(0,maxt,tstep)
glucose_out = odeint(glucose, x0, t, args=(params,))
plt.plot(t,glucose_out)
plt.legend(['blood glucose', 'insulin level'])
plt.ylabel('Blood Glucose Level mmol/L , Blood Insulin 10pmol/L')
plt.xlabel('Time/h')
plt.title('Glucose-Insulin Regulation Model')
How do I get rid of the error to produce a graph?

Related

Odeint problem in model: lsoda-- repeated occurrences of illegal input && lsoda-- at start of problem, too much accuracy

I need help to solve a ODE system using odeint or any workaround that works. I`m trying to model a ODE system descriving the beheaviour of a cilinder on a mechanichal arm, using Lagrangian mechanics I got the following 2nd order ODE system:
$$\ddot{x} = x*\dot{\phi}^2 - g*(sin(\phi) +cos(\phi))$$
$$\ddot{\phi} = \frac{1}{2*\dot{x}*m_c}*(\frac{k*i}{x}-\frac{m_b*L*\dot{\phi}}{2}-g*cos(\phi)*(m_c*x-m_b*L/2))$$
Then I transformed it to a 4x4 1st order ODE system y linearized 2 equations aroun initial condition, to make it more "solveable".
In python I`wrote the folllowing:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# source: https://apmonitor.com/pdc/index.php/Main/SolveDifferentialEquations
g, mc, mb, k, L = (9.8, 0.5, 1.3, 2, 1.2)
def model(z, t, i, z0):
global g, mc, mb, k, L
#ODE variables
x1 = z[0]
y1 = z[1]
x2 = z[2]
y2 = z[3]
#ODE initial conditions
zx1 = z0[0]
zy1 = z0[1]
zx2 = z0[2]
zy2 = z0[3]
#Diferential for linealization around I.C.
dx1 = z[0]-z0[0]
dy1 = z[1]-z0[1]
dx2 = z[2]-z0[2]
dy2 = z[3]-z0[3]
def w1(zx1, zy1, zx2, zy2):
global g, mc, mb, k, L
return zx2*zy1**2-g*(np.sin(zy2)+np.cos(zy2))
def w2(zx1, zy1, zx2, zy2):
global g, mc, mb, k, L
return 1/(2*zx1*mc)*((k*i)/(zx2)-mb*zy2*L/2-g*np.cos(zy2*(mc*zx2-mb*L/2)))
dx2dt = x1
#dx1dt = x2*y1**2-g*(np.sin(y2)+np.cos(y2))
dx1dt = w1(zx1, zy1, zx2, zy2) + zy1**2*dx2+2*zx2 * \
zy1*dy1-g*(np.cos(zy2)-np.sin(zy2))*dy2
dy2dt = y1
#dy1dt = 1/(2*x1*mc)*((k*i)/(x2)-mb*y2*L/2-g*np.cos(y2*(mc*x2-mb*L/2)))
dy1dt = w2(zx1, zy1, zx2, zy2) - 1/(4*zx1**2*mc) * \
((k*i)/(zx2)-mb*zy2*L/2-g*np.cos(zy2*(mc*zx2-mb*L/2)))*dx1
+(k*i*np.log(abs(zx2))/(2*zx1*mc)-g*np.cos(zy2)*mc)*dx2-(mb*L) / \
(4*zx1*mc)*dy1+g*np.sin(zy2)*(mc*zx2-mb*L/2)*(2*zx1*mc)*dy2
dzdt = [dx1dt, dy1dt, dx2dt, dy2dt]
return dzdt
# initial condition
z0 = [0.01, 0.01, 0.8, np.pi/8]
# number of time points
n = 30
# time points
t = np.linspace(0, 1, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[:] = 1
# store solution
x1 = np.zeros(n)
y1 = np.zeros(n)
x2 = np.zeros(n)
y2 = np.zeros(n)
# record initial conditions
x1[0] = z0[0]
y1[0] = z0[1]
x2[0] = z0[2]
y2[0] = z0[3]
# solve ODE
for i in range(1, n):
# span for next time step
tspan = [t[i-1], t[i]]
# solve for next step
z = odeint(model, z0, tspan, args=((u[i], z0)) )
# store solution for plotting
if -np.pi/4 <= z[1][3] <= np.pi/4: # Angulo +/- Pi/4
u[i] = u[i-1] + 1
else:
u[i] = u[i-1]
if 0 <= z[1][2] <= L: # Se mantiene en el brazo
print("Se saliΓ³")
x1[i] = z[1][0]
y1[i] = z[1][1]
x1[i] = z[1][2]
y1[i] = z[1][3]
# Siguientes CI
z0 = z[1]
# plot results
plt.plot(t, u, 'g:', label='u(t)')
plt.plot(t, x2, 'b-', label='x(t)')
plt.plot(t, y2, 'r--', label='phi(t)')
plt.ylabel('Cilindro(x,phi)')
plt.xlabel('Tiempo(s)')
plt.legend(loc='best')
plt.show()
Then I`ve got the following error, telling me than too much accuracy is needed to solve my system:
lsoda-- at start of problem, too much accuracy
requested for precision of machine.. see tolsf (=r1)
in above message, r1 = NaN
lsoda-- repeated occurrences of illegal input
lsoda-- at start of problem, too much accuracy
requested for precision of machine.. see tolsf (=r1)
in above message, r1 = NaN
dy1dt = w2(zx1, zy1, zx2, zy2) - 1/(4*zx1**2*mc) * \
lsoda-- warning..internal t (=r1) and h (=r2) are
such that in the machine, t + h = t on the next step
(h = step size). solver will continue anyway
in above, r1 = 0.3448275862069D+00 r2 = 0.1555030227910D-28

Couple Differential Equations using Python

I am trying to solve a system of geodesics orbital equations using python. They are coupled ordinary equations. I've tried different approaches, but they all yielded me a wrong shape (the shape should be some periodic function when plotting r and phi). Any idea on how to do this?
Here are my constants
G = 4.30091252525 * (pow(10, -3)) #Gravitational constant in (parsec*km^2)/(Ms*sec^2)
c = 0.0020053761 #speed of light , AU/sec
M = 170000 #mass of the central body, in solar masses
m = 10 #mass of the orbiting body, in solar masses
rs = 2 * G * M / pow(c, 2) #Schwarzschild radius
Lz= 0.000024 #Angular momemntum
h = Lz / m #Just the constant in equation
E= 1.715488e-007 #energy
And initial conditions are:
Y(0) = rs
Phi(0) = math.pi
Orbital equations
The way I tried to do it:
def rhs(t, u):
Y, phi = u
dY = np.sqrt((E**2 / (m**2 * c**2) - (1 - rs / Y) * (c**2 + h**2 / Y**2)))
dphi = L / Y**2
return [dY, dphi]
Y0 = np.array([rs,math.pi])
sol = solve_ivp(rhs, [1, 1000], Y0, method='Radau', dense_output=True)
It seems like you are looking at the spacial coordinates in an invariant plane of the geodesic equations of an object moving in Schwarzschild gravity.
One can use many different methods, which preserve as much of the underlying geometric structure of the model as possible, like symplectic geometric integrators or perturbation theory. As Lutz Lehmann pointed out in the comments, the default method for 'solve_ivp' uses as default the Dormand-Prince (4)5 stepper that utilizes the extrapolation mode, that is, the order 5 step, with the step size selection driven by the error estimate of the order 4 step.
Warning: your initial condition for Y equals Schwarzschild's radius, so these equations may fail or require special treatment (especially the time component of the equations, which you have not included here!) It may be that you have to switch to different coordinates, that remove the singularity at the even horizon. Moreover, the solutions may not be periodic curves, but quasi-periodic, so they may not close up nicely.
For a quick and dirty treatment, but possibly a fairly accurate one, I would differentiate the first equation
(dr / dtau)^2 = (E2_mc2 - c2) + (2*GM)/r - (h^2)/(r^2) + (r_schw*h^2)/(r^3)
with respect to the proper time tau, then cancel out the first derivative dr / dtau with respect to r on both sides, and end up with an equation with second derivative for the radius r on the left. Then turn this second derivative equation into a pair of first derivative equations for r and its rate of change v, i.e
dphi / dtau = h / (r^2)
dr / dtau = v
dv / dtau = - GM / (r^2) + h^2 / (r^3) - 3*r_schw*(h^2) / (2*r^4)
and calculate from the original equation for r and its first derivative dr / dtau an initial value for the rate of change v = dr / dtau, i.e. I would solve for v the equations with r=r0:
(v0)^2 = (E2_mc2 - c2) + (2*GM)/r0 - (h^2)/(r0^2) + (r_schw*h^2)/(r0^3)
Maybe some kind of python code like this may work:
import math
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
#from ode_helpers import state_plotter
# u = [phi, Y, V, t] or if time is excluded
# u = [phi, Y, V]
def f(tau, u, param):
E2_mc2, c2, GM, h, r_schw = param
Y = u[1]
f_phi = h / (Y**2)
f_Y = u[2] # this is the dr / dt auxiliary equation
f_V = - GM / (Y**2) + h**2 / (Y**3) - 3*r_schw*(h**2) / (2*Y**4)
#f_time = (E2_mc2 * Y) / (Y - r_schw) # this is the equation of the time coordinate
return [f_phi, f_Y, f_V] # or [f_phi, f_Y, f_V, f_time]
# from the initial value for r = Y0 and given energy E,
# calculate the initial rate of change dr / dtau = V0
def ivp(Y0, param, sign):
E2_mc2, c2, GM, h, r_schw = param
V0 = math.sqrt((E2_mc2 - c2) + (2*GM)/Y0 - (h**2)/(Y0**2) + (r_schw*h**2)/(Y0**3))
return sign*V0
G = 4.30091252525 * (pow(10, -3)) #Gravitational constant in (parsec*km^2)/(Ms*sec^2)
c = 0.0020053761 #speed of light , AU/sec
M = 170000 #mass of the central body, in solar masses
m = 10 #mass of the orbiting body, in solar masses
Lz= 0.000024 #Angular momemntum
h = Lz / m #Just the constant in equation
E= 1.715488e-007 #energy
c2 = c**2
E2_mc2 = (E**2) / (c2*m**2)
GM = G*M
r_schw = 2*GM / c2
param = [E2_mc2, c2, GM, h, r_schw]
Y0 = r_schw
sign = 1 # or -1
V0 = ivp(Y0, param, sign)
tau_span = np.linspace(1, 1000, num=1000)
u0 = [math.pi, Y0, V0]
sol = solve_ivp(lambda tau, u: f(tau, u, param), [1, 1000], u0, t_eval=tau_span)
Double check the equations, mistakes and inaccuracies are possible.

Solving set of ODEs with Scipy

I am trying to develop an algorithm (use scipy.integrate.odeint()) that predicts the changing concentration of cells, substrate and product (i.e., 𝑋, 𝑆, 𝑃) over time until the system reaches steady- state (~100 or 200 hours). The initial concentration of cells in the bioreactor is 0.1 𝑔/𝐿 and there is no glucose or product in the reactor initially. I want to test the algorithm for a range of different flow rates, 𝑄, between 0.01 𝐿/β„Ž and 0.25 𝐿/β„Ž and analyze the impact of the flow rate on product production (i.e., 𝑄 β‹… 𝑃 in 𝑔/β„Ž). Eventually, I would like to generate a plot that shows product production rate (y-axis) versus flow rate, 𝑄, on the x-axis. My goal is to estimate the flow rate that results in the maximum (or critical) production rate. This is my code so far:
from scipy.integrate import odeint
import numpy as np
# Constants
u_max = 0.65
K_s = 0.14
K_1 = 0.48
V = 2
X_in = 0
S_in = 4
Y_s = 0.38
Y_p = 0.2
# Variables
# Q - Flow Rate (L/h), value between 0.01 and 0.25 that produces best Q * P
# X - Cell Concentration (g/L)
# S - The glucose concentration (g/L)
# P - Product Concentration (g/L)
# Equations
def func_dX_dt(X, t, S):
u = (u_max) / (1 + (K_s / S))
dX_dt = (((Q * S_in) - (Q * S)) / V) + (u * X)
return dX_dt
def func_dS_dt(S, t, X):
u = (u_max) / (1 + (K_s / S))
dS_dt = (((Q * S_in) - (Q * S)) / V) - (u * (X / Y_s))
return dS_dt
def func_dP_dt(P, t, X, S):
u = (u_max) / (1 + (K_s / S))
dP_dt = ((-Q * P) / V) - (u * (X / Y_p))
return dP_dt
t = np.linspace(0, 200, 200)
# Q placeholder
Q = 0.01
# Attempt to solve the Ordinary differential equations
sol_dX_dt = odeint(func_dX_dt, 0.1, t, args=(S,))
sol_dS_dt = odeint(func_dS_dt, 0.1, t, args=(X,))
sol_dP_dt = odeint(func_dP_dt, 0.1, t, args=(X,S))
In the programs current state there does not seem to be be a way to generate the steady state value for P. I attempted to make this modification to get the value of X.
sol_dX_dt = odeint(func_dX_dt, 0.1, t, args=(odeint(func_dS_dt, 0.1, t, args=(X,)),))
It produces the error:
NameError: name 'X' is not defined
At this point I am not sure how to move forward.
(Edit 1: Added Original Equations)
First Equation
Second Equation and Third Equation
You do not have to apply the functions to each part but return a tuple of the derivatives as I show below:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
Q = 0.01
V = 2
Ys = 0.38
Sin = 4
Yp = 0.2
Xin = 0
umax = 0.65
Ks = 0.14
K1 = 0.48
def mu(S, umax, Ks, K1):
return umax/((1+Ks/S)*(1+S/K1))
def dxdt(x, t, *args):
X, S, P = x
Q, V, Xin, Ys, Sin, Yp, umax, Ks, K1 = args
m = mu(S, umax, Ks, K1)
dXdt = (Q*Xin - Q*X)/V + m*X
dSdt = (Q*Sin - Q*S)/V - m*X/Ys
dPdt = -Q*P/V - m*X/Yp
return dXdt, dSdt, dPdt
t = np.linspace(0, 200, 200)
X0 = 0.1
S0 = 0.1
P0 = 0.1
x0 = X0, S0, P0
sol = odeint(dxdt, x0, t, args=(Q, V, Xin, Ys, Sin, Yp, umax, Ks, K1))
plt.plot(t, sol[:, 0], 'r', label='X(t)')
plt.plot(t, sol[:, 1], 'g', label='S(t)')
plt.plot(t, sol[:, 2], 'b', label='P(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.show()
Output:

Smoothing signal - convolution

I have an iterative model in Python which generates at signal using a function which contains a derivative. As the model iterates the signal becomes noisy - I suspect it may be an issue with computing the numerical derivative. I've tried to smooth this by applying a low-pass filter, convolving the noisy signal with a Gaussian kernel. I use the code snippet:
nw = 256
std = 40
window = gaussian(nw, std, sym=True)
filtered = convolve(current, window, mode='same') / np.sum(window)
where current is my signal, and gaussian and convolve have been imported from scipy. This seems to give a slight improvement, and the first 2 or 3 iterations appear very smooth. However, after that the signal becomes extremely noisy again, despite the fact that the low-pass filter is positioned inside the iterative loop.
Can anyone suggest where I might be going wrong or how I could better tackle this problem? Thanks.
EDIT: As suggested I've included the code I'm using below. At 5 iterations the noise on the signal is clearly apparent.
import numpy as np
from scipy import special
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from scipy.signal import convolve
from scipy.signal import gaussian
# Constants
B = 426400E-9 # tesla
R = 71723E3
Rkm = R / 1000.
Omega = 1.75e-4 #8.913E-4 # rads/s
period = (2. * np.pi / Omega) / 3600. # Gets period in hours
Bj = 2.0 * B
mdot = 1000.
sigmapstar = 0.05
# Create rhoe array
rho0 = 5.* R
rho1 = 100. * R
rhoe = np.linspace(rho0, rho1, 2.E5)
# Define flux function and z component of equatorial field strength
Fe = B * R**3 / rhoe
Bze = B * (R/rhoe)**3
def derivs(u, rhoe, p):
"""Computes the derivative"""
wOmegaJ = u
Bj, sigmapstar, mdot, B, R = p
# Compute the derivative of w/omegaJ wrt rhoe (**Fe and Bjz have been subbed)
dwOmegaJ = (((8.0*np.pi*sigmapstar*B**2 * (R**6)) / (mdot * rhoe**5)) \
*(1.0-wOmegaJ) - (2.*wOmegaJ/rhoe))
res = dwOmegaJ
return res
its = 5 # number of iterations to perform
i = 0
# Loop to iterate
while i < its:
# Define the initial condition of rigid corotation
wOmegaJ_0 = 1
params = [Bj, sigmapstar, mdot, B, R]
init = wOmegaJ_0
# Compute numerical solution to Hill eqn
u = odeint(derivs, init, rhoe, args=(params,))
wOmega = u[:,0]
# Calculate I_rho
i_rho = 8. * np.pi * sigmapstar * Omega * Fe * ( 1. - wOmega)
dx = rhoe[1] - rhoe[0]
differential = np.gradient(i_rho, dx)
jpara = 1. * differential / (4 * np.pi * rhoe * Bze )
jpari = 2. * B * para
# Remove infinity and NaN values)
jpari[~np.isfinite(jpari)] = 0.0
# Convolve to smooth curve
nw = 256
std = 40
window = gaussian(nw, std, sym=True)
filtered = convolve(jpari, window, mode='same') /np.sum(window)
jpari = filtered
# Pedersen conductivity as function of jpari
sigmapstar0 = 0.05
jstar = 0.01e-6
jstarstar = 0.25e-6
s1 = 0.1e6#0.1e6 # (Am^-2)^-1
s2 = 9.9e6 # (Am^-2)^-1
n = 8.
# Calculate news sigmapstar. Realistic conductivity
sigmapstarNew = sigmapstar0 + 0.5 * (s1 + s2/(1 + (jpari/jstarstar)**n)**(1./n)) * (np.sqrt(jpari**2 + jstar**2) + jpari)
sigmapstarNew = sigmapstarNew
diff = np.abs(sigmapstar - sigmapstarNew) / sigmapstar * 100
diff = max(diff)
sigmapstar = 0.5* sigmapstar + 0.5* sigmapstarNew # Weighted averaging
i += 1
print diff
# Plot jpari
ax = plt.subplot(111)
ax.plot(rhoe/R, jpari * 1e6)
ax.axhline(0, ls=':')
ax.set_xlabel(r'$\rho_e / R_{UCD}$')
ax.set_ylabel(r'$j_{\parallel i} $ / $ \mu$ A m$^{-2}$')
ax.set_xlim([0,80])
ax.set_ylim(-0.01,0.01)
plt.locator_params(nbins=5)
plt.draw()
plt.show()

Python scipy.optimize.minimize gives ZeroDivisionError

I am trying to implement SABR (Stochastic alpha, beta, rho) in Python to calculate implied volatility. This link here explains SABR very accurately and concisely starting on slide 17: http://lesniewski.us/papers/presentations/MIT_March2014.pdf
The method seems easy enough, but the problem I am having is that I am getting a ZeroDivisonError every time I run the program. I believe this may be because I am choosing my initial alpha, rho, and sigma0 incorrectly during calibration. However, I cannot find online how to choose the initial values to guarantee that a minimum will be found.
Here is my code:
# args = [alpha, rho, sigma0]
# The other parameters (T, K, F0, beta, rho, marketVol) are globals
def calcImpliedVol(args):
alpha = args[0]
rho = args[1]
sigma0 = args[2]
# From MIT powerpoint, slide 21
Fmid = (F0 + K) / 2.0
gamma1 = 1.0 * beta / Fmid
gamma2 = 1.0 * beta * (beta - 1) / Fmid**2
xi = 1.0 * alpha / (sigma0 * (1 - beta)) * (F0**(1-beta) - K**(1-beta))
e = T * alpha**2 # From MIT powerpoint, slide 19
# From MIT powerpoint, slide 21
impliedVol = \
1.0 * alpha * log(F0/K) / D(rho, xi) * \
(1 + ((2 * gamma2 - gamma1**2 + 1 / Fmid**2)/24.0 * (sigma0 * Fmid**beta / alpha)**2 + \
(rho * gamma1 / 4.0) * (sigma0 * Fmid**beta / alpha) + ((2 - 3 * rho**2) / 24.0)) * e) - \
marketVol
# Returns lambda function in terms of alpha, rho, sigma0
return impliedVol;
# From MIT powerpoint, slide 21
def D(rho, xi):
result = log((sqrt(1 - 2 * rho * xi + xi**2) + xi - rho) / (1-rho))
return result
# Find optimal alpha, rho, sigma0 that minimizes calcImpliedVol - marketVol
def optimize():
result = optimize.minimize(calcImpliedVol, [alpha_init, rho_init, sigma0_init])
return result
Thanks so, so much for any help!
This is a little late but bounding is the right way to go:
bounds = [(0.0001, None), (-0.9999, 0.9999), (0.0001, None)]
x_solved = minimize(obj_func, initial_guess, args=(mkt_vols, F, K, tau, beta),
method='L-BFGS-B', bounds=bounds, tol=0.00001)
alpha represents the base volatility (atm vol can be used here to as an initialization) so it is bounded by 0.0. rho is the correlation between the axes so it is bounded by -1 and 1. nu (vol of volatility) is bounded on the downside by 0.0.
The coefficient tuple is returned with:
x_solved.x
Work with bounding the search intervals.

Categories