MMSB: Mathematical Modeling in Systems Biology / Sep 15 2020
Remix of Python by
Nextjournal
Solving Ordinary Differential Equations (ODEs)
Python
scipy.integrate.odeint()
Scipy's documentation
Exponential decays
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
%matplotlib inline
# function that returns dy/dt
def model(y,t,k):
dydt = -k * y
return dydt
# initial condition
y0 = 5
# time points
t = np.linspace(0, 20)
# solve ODEs
y1 = odeint(model,y0,t,args=(0.1,))
y2 = odeint(model,y0,t,args=(0.2,))
y3 = odeint(model,y0,t,args=(0.5,))
# plot results
plt.figure()
plt.plot(t,y1,'r-',linewidth=2,label='k=0.1')
plt.plot(t,y2,'b--',linewidth=2,label='k=0.2')
plt.plot(t,y3,'g:',linewidth=2,label='k=0.5')
plt.xlabel('time')
plt.ylabel('y(t)')
plt.legend()
2.7s
Python
<matplotlib.legend.Legend at 0x7f9de86881d0>
Hodgkin-Huxley electrophysiology model
"""
Hodgkin-Huxley model of excitable barnacle muscle fiber
reviewed in Rinzel (1990) Bulletin of Mathematical Biology 52 pp. 5-23.
"""
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from math import exp, expm1
def get_iStim(t):
if 20 < t <= 21:
return -6.65
elif 60 < t <= 61:
return -6.86
else:
return 0
# Model
def hh_rhs(y, t, p):
# Constants
E_N = p['E_N'] # Reversal potential of Na
E_K = p['E_K'] # Reversal potential of K
E_LEAK = p['E_LEAK'] # Reversal potential of leaky channels
G_N_BAR = p['G_N_BAR'] # Max. Na channel conductance
G_K_BAR = p['G_K_BAR'] # Max. K channel conductance
G_LEAK = p['G_LEAK'] # Max. leak channel conductance
C_M = p['C_M'] # membrane capacitance
# Equations
v, m, h, n = y
mAlfaV = -0.10 * (v + 35)
mAlfa = mAlfaV / expm1(mAlfaV)
mBeta = 4.0 * exp(-(v + 60) / 18.0)
dm = -(mAlfa + mBeta) * m + mAlfa
hAlfa = 0.07 * exp(-(v+60)/20)
hBeta = 1 / (exp(-(v+30)/10) + 1)
dh = -(hAlfa + hBeta) * h + hAlfa
iNa = G_N_BAR * (v - E_N) * (m**3) * h
nAlfaV = -0.1 * (v+50)
nAlfa = 0.1 * nAlfaV / expm1(nAlfaV)
nBeta = 0.125 * exp( -(v+60) / 80)
dn = -(nAlfa + nBeta) * n + nAlfa
iK = G_K_BAR * (v - E_K) * (n**4)
iLeak = G_LEAK * (v - E_LEAK)
iSt = get_iStim(t)
dv = -(iNa + iK + iLeak + iSt) / C_M
return [dv, dm, dh, dn]
# Initial conditions
y0 = v, m, h, n = -59.8977, 0.0536, 0.5925, 0.3192
# Parameters
p = {'E_N': 55, # Reversal potential of Na
'E_K': -72, # Reversal potential of K
'E_LEAK': -49, # Reversal potential of leaky channels
'G_N_BAR': 120,# Max. Na channel conductance
'G_K_BAR': 36, # Max. K channel conductance
'G_LEAK': 0.3, # Max. leak channel conductance
'C_M': 1.0} # membrane capacitance
# time span
tStart, tEnd = 0, 100
N_POINTS = 100+1
ts = np.linspace(tStart, tEnd, N_POINTS)
# Solve the ODEs
sol = odeint(hh_rhs, y0, ts, args=(p,), tcrit=[20, 21, 60, 61])
# Plotting
fig, axs = plt.subplots(nrows=2, figsize=(10, 15))
axs[0].plot(ts, sol[:, 0], 'k-', linewidth=2)
axs[0].set_xlabel("Time (ms)")
axs[0].set_ylabel("Membrane voltage (mV)")
axs[1].plot(ts, sol[:, 1:], linewidth=2, label=["m", "h", "n"])
axs[1].set_xlabel("Time (ms)")
axs[1].set_ylabel("Gating variables")
fig
1.3s
Python
PySB
"PySB is a framework for building mathematical models of biochemical systems as Python programs"
Website: http://pysb.org/
Publication: Lopez, C. F., Muhlich, J. L., Bachman, J. A. & Sorger, P. K. Programming biological models in Python using PySB. Mol Syst Biol 9, (2013). doi:10.1038/msb.2013.1
conda install -c alubbock pysb kappa --yes
40.2s
Bash in Python
from pysb import *
from pysb.simulator import ScipyOdeSimulator
from pylab import linspace, plot, xlabel, ylabel, gcf
import matplotlib.pyplot as plt
# A simple model with a reversible binding rule
Model()
# Declare the monomers
Monomer('L', ['s'])
Monomer('R', ['s'])
# Declare the parameters
Parameter('L_0', 100)
Parameter('R_0', 200)
Parameter('kf', 1e-3)
Parameter('kr', 1e-3)
# Declare the initial conditions
Initial(L(s=None), L_0)
Initial(R(s=None), R_0)
# Declare the binding rule
Rule('L_binds_R', L(s=None) + R(s=None) | L(s=1) % R(s=1), kf, kr)
# Observe the complex
Observable('LR', L(s=1) % R(s=1))
time = linspace(0, 40, 100)
print("Simulating...")
sim_result = ScipyOdeSimulator(model, time).run()
# Plot the trajectory of LR
plt.figure()
plot(time, sim_result.observables['LR'])
xlabel('Time (seconds)')
ylabel('Amount of LR')
gcf()
7.8s
Python
Enzyme kinetics
from pysb import Model, Monomer, Parameter, Initial, Rule, Observable
from pysb.macros import *
# Create an instance of empty model
Model()
# Create a monomer named 'enzyme' that only has one attribute, called 'binding1'.
Monomer('enzyme', ['binding1'])
# Create a monomer named 'protein' that has two attributes, called 'binding1'(bound to enzyme or not) and state (substrate or product).
Monomer('protein', ['binding', 'state'], {'state': ['sub','pro']})
# Define a forward, reverse and catalysis parameters (kf, kr, kc)
Parameter('kf',0.003)
Parameter('kr',0.001)
Parameter('kc',0.002)
# Define a binding rule where the unbound enzyme binds the protein in the substrate state. | = reversible reaction, % = bounded state
Rule('binding', enzyme(binding1=None) + protein(state='sub', binding=None)
| enzyme(binding1=1) % protein(state='sub', binding=1), kf, kr)
# Create a catalysis rule where the complex dissociates and the protein change state to product (the enzyme is left unaltered). >> = irreversible reaction
Rule('dissociation', enzyme(binding1=1) % protein(state='sub', binding=1)
>> enzyme(binding1=None) + protein(state='pro', binding=None), kc)
# Define the initial conditions for the two objects using parameters.
Parameter('enzyme_0', 100)
Parameter('protein_0', 50)
Initial(enzyme(binding1=None), enzyme_0 )
Initial(protein(binding=None, state='sub') , protein_0)
# Define the observables: total enzyme, product and the complex
Observable('e_total', enzyme())
Observable('e_free', enzyme(binding1=None))
Observable('substrate', protein(binding=None, state='sub'))
Observable('product', protein(binding=None, state='pro'))
Observable('complex', enzyme(binding1=1) %
protein(binding=1, state='sub'))
# run a simulation
from pysb.integrate import odesolve
import matplotlib.pyplot as plt
import numpy as np
tspan = np.linspace(0, 100, 100)
y = odesolve(model, tspan)
plt.figure()
plt.plot(tspan, y['substrate'], label="substrate")
plt.plot(tspan, y['e_total'], label="e_total")
plt.plot(tspan, y['e_free'], label="e_free")
plt.plot(tspan, y['product'], label="product")
plt.plot(tspan, y['complex'], label="complex")
plt.xlabel('time')
plt.ylabel('population')
plt.ylim(0,110)
plt.legend(loc='best')
plt.gcf()
2.6s
Python
Julia
See Solving ODEs in Julia. (from the official documentation)