In [1]:
import inspect
from math import sqrt, pi
import numpy as np
import pandas as pd
from bokeh.io import show, output_notebook, push_notebook
from bokeh.plotting import figure
from ipywidgets import interact
from scipy.integrate import quad
In [2]:
output_notebook()
The particles are here assumed to interact via a Lennard-Jones and a screened Coulomb potential,
$$ \beta w(r) = \frac{\lambda_B z^2}{r} e^{-r/\lambda_D} + 4\beta \varepsilon_{LJ} \left ( \left ( \frac{\sigma}{r}\right )^{12} - \left ( \frac{\sigma}{r}\right )^{6}\right ) $$where $\lambda_B$ and $\lambda_D$ are the Bjerrum and Debye lengths, respectively. Any potential may in principle be given and must return the energy in units of $k_BT$.
potential_
r
r"$ \mu $"
is convenient when writing latex, because in normal strings the backslash acts as an escape character)
In [3]:
# Debye-Huckel
def potential_Debye_Huckel(r, z, D):
r"""$\frac{\lambda_B z^2}{r} e^{-r/\lambda_D}$"""
lB = 7.0 # Bjerrum length, angstroms
return lB * z**2 * np.exp(-r/D) / r
# Lennard-Jones
def potential_Lennard_Jones(r, eps, sigma):
r"""$4\beta \varepsilon_{LJ} \left ( \left ( \frac{\sigma}{r}\right )^{12} - \left ( \frac{\sigma}{r}\right )^{6}\right )$"""
return 4 * eps * ( (sigma/r)**12 - (sigma/r)**6 )
# Total potential
def potential_Combined(r, z, D, eps, sigma):
r"""$\frac{\lambda_B z^2}{r} e^{-r/\lambda_D} + 4\beta \varepsilon_{LJ} \left ( \left ( \frac{\sigma}{r}\right )^{12} - \left ( \frac{\sigma}{r}\right )^{6}\right )$"""
return potential_Debye_Huckel(r, z, D) + potential_Lennard_Jones(r, eps, sigma)
Here we integrate the above pair potential to get the average interaction energy per particle, assuming that the pair correlation function, $g(r)$, can be described by a simple step function, zero when $r<\sigma$, unity otherwise: $$ \hat{a} = -\frac{1}{2} \int_{\sigma}^{\infty} 4\pi w(r) r^2 dr $$
In this Notebook we simply do the integration numerically so that we can use arbitrary pair potentials. From this we calculate the potential, $μ$, versus density, $n$, using,
$$ \beta \, \mu_{gvdW} = \ln \left( \frac{1}{y - y_0} \right) + \frac{y}{y-y_0} - 2 \frac{\hat{a}}{y} $$From this we calculate the pressure, $p$, versus density, $n$, using,
where $y=1/n$ and $y_0=\pi \sigma^2/2$ is the particle area.
For reference we'll also plot Equation of State for an ideal system (van 't Hoff), $\beta \mu_{ideal}= \ln (1/y)$, where $\beta = 1/k_BT$.
In [29]:
def ahat(potential, **parameters):
sigma = parameters['sigma']
# extract the relevant parameters for the potential
parameters = {k:v for k,v in parameters.items() if k in inspect.signature(potential).parameters}
def integrand(r):
return potential(r, **parameters) * r**2
integral, error = quad(integrand, sigma, np.infty, limit=50)
return -2 * pi * integral
def mu_ideal(n):
return np.log(n)
def mu_gvdw(n, z, D, eps, sigma, potential=potential_Combined):
y0 = pi*sigma**2 / 2 # excluded volume
y = 1 / n
a = ahat(potential, z=z, D=D, eps=eps, sigma=sigma)
return -np.log(y-y0) + y0 / (y - y0) - 2 * a / y
In [30]:
n = np.linspace(1e-4, 1e-3, 100);
def update(eps=1.0, sigma=4.0, z=1.0, Cs=0.3, potential=potential_Combined):
D = 3.04/sqrt(Cs)
gvdw_line.data_source.data["y"] = mu_gvdw(n, z, D, eps, sigma, potential)
push_notebook(handle=potfig_handle)
In [31]:
potfig = figure(
title="Chemical potential",
plot_height=300,
plot_width=600,
x_axis_label="Number density n",
y_axis_label="Potential (k T)")
ideal_line = potfig.line(n, mu_ideal(n), legend="Ideal")
gvdw_line = potfig.line(n, mu_gvdw(n, z=0, D=3.04/sqrt(0.3), eps=1, sigma=4, potential=potential_Combined), color="green", legend="GvdW")
potfig_handle = show(potfig, notebook_handle=True)
In [19]:
_potentials = {fname[10:]: func for fname, func in globals().items() if fname.startswith("potential_")}
interact(update, eps=(0.0, 10.0, 0.1), sigma=(0, 5, 0.1), z=(0.0, 3, 1.0), Cs=(1e-3, 1.0, 0.1), potential=_potentials);
In [10]:
with open("datafile.csv", "wt") as stream:
stream.write("""\
length potential proteins density
1.414000000000000000e+03 1.429585460731450097e-01 2.000000000000000000e+01 1.000302091231552026e+03
9.990000000000000000e+02 2.990882091428900269e-01 2.000000000000000000e+01 2.004006008010011783e+03
8.160000000000000000e+02 4.684432472751309806e-01 2.000000000000000000e+01 3.003652441368703876e+03
6.320000000000000000e+02 8.629727385734929923e-01 2.000000000000000000e+01 5.007210382951449901e+03
5.340000000000000000e+02 1.353602607621670062e+00 2.000000000000000000e+01 7.013704779138435697e+03
4.710000000000000000e+02 1.970895704549270100e+00 2.000000000000000000e+01 9.015466031977857710e+03
4.260000000000000000e+02 2.788653065634310035e+00 2.000000000000000000e+01 1.102074103462716812e+04
3.920000000000000000e+02 3.842403663548089821e+00 2.000000000000000000e+01 1.301541024573094546e+04""")
In [11]:
df = pd.read_csv("datafile.csv", delimiter="(?:\s+|,)", engine="python")