Skip to content

Commit

Permalink
Merge 3441d7d into 1c7c971
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew McCluskey committed Jul 2, 2018
2 parents 1c7c971 + 3441d7d commit b01fc10
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 14 deletions.
4 changes: 2 additions & 2 deletions examples/molecular_dynamics.ipynb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pylj.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pylj/__init__.py
pylj/_testutils.py
pylj/mc.py
pylj/md.py
pylj/pairwise.py
pylj/sample.py
pylj/util.py
pylj.egg-info/PKG-INFO
Expand Down
14 changes: 10 additions & 4 deletions pylj/md.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import numpy as np
from pylj import comp, util
from pylj import util
try:
from pylj import comp as heavy
except ImportError:
print("WARNING, using slow force and energy calculations")
from pylj import pairwise as heavy


def initialise(number_of_particles, temperature, box_length, init_conf, timestep_length=1e-14):
Expand Down Expand Up @@ -33,7 +38,7 @@ def initialise(number_of_particles, temperature, box_length, init_conf, timestep
v = (v - np.average(v)) * np.sqrt(2 * system.init_temp / v2sum)
system.particles['xvelocity'] = v[:, 0]
system.particles['yvelocity'] = v[:, 1]
system.particles, system.distances, system.forces, system.energies = comp.compute_forces(system.particles,
system.particles, system.distances, system.forces, system.energies = heavy.compute_forces(system.particles,
system.box_length,
system.cut_off)
return system
Expand Down Expand Up @@ -70,7 +75,7 @@ def velocity_verlet(particles, timestep_length, box_length, cut_off):
box_length)
xacceleration_store = list(particles['xacceleration'])
yacceleration_store = list(particles['yacceleration'])
particles, distances, forces, energies = comp.compute_forces(particles, box_length, cut_off)
particles, distances, forces, energies = heavy.compute_forces(particles, box_length, cut_off)
[particles['xvelocity'], particles['yvelocity']] = update_velocities([particles['xvelocity'],
particles['yvelocity']],
[xacceleration_store, yacceleration_store],
Expand Down Expand Up @@ -103,7 +108,7 @@ def sample(particles, box_length, initial_particles, system):
"""
temperature_new = util.calculate_temperature(particles)
system.temperature_sample = np.append(system.temperature_sample, temperature_new)
pressure_new = comp.calculate_pressure(particles, box_length, temperature_new, system.cut_off)
pressure_new = heavy.calculate_pressure(particles, box_length, temperature_new, system.cut_off)
msd_new = util.calculate_msd(particles, initial_particles, box_length)
system.pressure_sample = np.append(system.pressure_sample, pressure_new)
system.force_sample = np.append(system.force_sample, np.sum(system.forces))
Expand Down Expand Up @@ -162,3 +167,4 @@ def update_velocities(velocities, accelerations_old, accelerations_new, timestep
velocities[0] += 0.5 * (accelerations_old[0] + accelerations_new[0]) * timestep_length
velocities[1] += 0.5 * (accelerations_old[1] + accelerations_new[1]) * timestep_length
return [velocities[0], velocities[1]]

189 changes: 189 additions & 0 deletions pylj/pairwise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import numpy as np

def compute_forces(particles, box_length, cut_off):
"""Calculates the forces and therefore the accelerations on each of the particles in the simulation. This uses a
12-6 Lennard-Jones potential model for Argon with values:
- A = 1.363e-134 J m :math:`^{12}`
- B = 9.273e-78 J m :math:`^6`
Parameters
----------
particles: util.particle_dt, array_like
Information about the particles.
box_length: float
Length of a single dimension of the simulation square, in Angstrom.
cut_off: float
The distance greater than which the forces between particles is taken as zero.
Returns
-------
util.particle_dt, array_like
Information about particles, with updated accelerations and forces.
float, array_like
Current distances between pairs of particles in the simulation.
float, array_like
Current forces between pairs of particles in the simulation.
float, array_like
Current energies between pairs of particles in the simulation.
"""
particles['xaccleration'] = np.zeros(particles['xaccleration'].size)
particles['yaccleration'] = np.zeros(particles['yaccleration'].size)
pairs = int((particles['xaccleration'].size - 1) * particles['xaccleration'].size / 2)
forces = np.zeros(pairs)
distances = np.zeros(pairs)
energies = np.zeros(pairs)
k = 0
A = 1.363e-134 # joules / metre ^ {12}
B = 9.273e-78 # joules / meter ^ {6}
atomic_mass_unit = 1.660539e-27 # kilograms
mass_of_argon_amu = 39.948 # amu
mass_of_argon = mass_of_argon_amu * atomic_mass_unit # kilograms
for i in range(0, particles['xposition'].size-1):
for j in range(i, particles['xposition'].size):
dx = particles['xposition'][i] - particles['xposition'][j]
dy = particles['yposition'][i] - particles['yposition'][j]
if np.abs(dx) > 0.5 * box_length:
dx *= 1 - box_length / np.abs(dx)
if np.abs(dy) > 0.5 * box_length:
dy *= 1 - box_length / np.abs(dy)
dr = np.sqrt(dx * dx + dy * dy)
distances[k] = dr
if dr <= cut_off:
inv_dr_1 = 1.0 / dr
inv_dr_6 = np.power(inv_dr_1, 6)
f = (12 * A * (inv_dr_1 * inv_dr_6 * inv_dr_6) - 6 * B * (inv_dr_1 * inv_dr_6))
forces[k] = f
e = (A * (inv_dr_6 * inv_dr_6) - B * inv_dr_6)
energies[k] = e
particles['xacceleration'][i] += (f * dx / dr) / mass_of_argon
particles['yacceleration'][i] += (f * dy / dr) / mass_of_argon
particles['xacceleration'][j] -= (f * dx / dr) / mass_of_argon
particles['yacceleration'][j] -= (f * dy / dr) / mass_of_argon
else:
forces[k] = 0.
energies[k] = 0.
k += 1
return particles, distances, forces, energies

def compute_energy(particles, box_length, cut_off):
"""Calculates the total energy of the simulation. This uses a
12-6 Lennard-Jones potential model for Argon with values:
- A = 1.363e-134 J m :math:`^{12}`
- B = 9.273e-78 J m :math:`^6`
Parameters
----------
particles: util.particle_dt, array_like
Information about the particles.
box_length: float
Length of a single dimension of the simulation square, in Angstrom.
cut_off: float
The distance greater than which the energies between particles is taken as zero.
Returns
-------
util.particle_dt, array_like
Information about particles, with updated accelerations and forces.
float, array_like
Current distances between pairs of particles in the simulation.
float, array_like
Current energies between pairs of particles in the simulation.
"""
pairs = int((particles['xaccleration'].size - 1) * particles['xaccleration'].size / 2)
distances = np.zeros(pairs)
energies = np.zeros(pairs)
k = 0
A = 1.363e-134 # joules / metre ^ {12}
B = 9.273e-78 # joules / meter ^ {6}
for i in range(0, particles['xpositions']-1):
for j in range(i, particles['xpositions']):
dx = particles['xposition'][i] - particles['xposition'][j]
dy = particles['yposition'][i] - particles['yposition'][j]
if np.abs(dx) > 0.5 * box_length:
dx *= 1 - box_length / np.abs(dx)
if np.abs(dy) > 0.5 * box_length:
dy *= 1 - box_length / np.abs(dy)
dr = np.sqrt(dx * dx + dy * dy)
distances[k] = dr
if dr <= cut_off:
inv_dr_1 = 1.0 / dr
inv_dr_6 = np.power(inv_dr_1, 6)
e = (A * (inv_dr_6 * inv_dr_6) - B * inv_dr_6)
energies[k] = e
else:
energies[k] = 0.
k += 1
return particles, distances, energies

def calculate_pressure(particles, box_length, temperature, cut_off):
r"""Calculates the instantaneous pressure of the simulation cell, found with the following relationship:
.. math::
p = \langle \rho k_b T \rangle + \bigg\langle \frac{1}{3V}\sum_{i}\sum_{j<i} \mathbf{r}_{ij}\mathbf{f}_{ij} \bigg\rangle
Parameters
----------
particles: util.particle_dt, array_like
Information about the particles.
box_length: float
Length of a single dimension of the simulation square, in Angstrom.
temperature: float
Instantaneous temperature of the simulation.
cut_off: float
The distance greater than which the forces between particles is taken as zero.
Returns
-------
float:
Instantaneous pressure of the simulation.
"""
pres = 0.
A = 1.363e-134 # joules / metre ^ {12}
B = 9.273e-78 # joules / meter ^ {6}
for i in range(0, particles['xpositions'] - 1):
for j in range(i, particles['xpositions']):
dx = particles['xposition'][i] - particles['xposition'][j]
dy = particles['yposition'][i] - particles['yposition'][j]
if np.abs(dx) > 0.5 * box_length:
dx *= 1 - box_length / np.abs(dx)
if np.abs(dy) > 0.5 * box_length:
dy *= 1 - box_length / np.abs(dy)
dr = np.sqrt(dx * dx + dy * dy)
distances[k] = dr
if dr <= cut_off:
inv_dr_1 = 1.0 / dr
inv_dr_6 = np.power(inv_dr_1, 6)
f = (12 * A * (inv_dr_1 * inv_dr_6 * inv_dr_6) - 6 * B * (inv_dr_1 * inv_dr_6))
pres += f * dr
boltzmann_constant = 1.3806e-23 # joules / kelvin
pres = 1. / (2 * box_length * box_length) * pres + (particles['xposition'].size / (box_length * box_length)
* boltzmann_constant * temperature)
return pres

def heat_bath(particles, temperature_sample, bath_temp):
r"""Rescales the velocities of the particles in the system to control the temperature of the simulation. Thereby
allowing for an NVT ensemble. The velocities are rescaled according the following relationship,
.. math::
v_{\text{new}} = v_{\text{old}} \times \sqrt{\frac{T_{\text{desired}}}{\bar{T}}}
Parameters
----------
particles: util.particle_dt, array_like
Information about the particles.
temperature_sample: float, array_like
The temperature at each timestep in the simulation.
bath_temp: float
The desired temperature of the simulation.
Returns
-------
util.particle_dt, array_like
Information about the particles with new, rescaled velocities.
"""
average_temp = np.average(temperature_sample)
particles['xvelocity'] = particles['xvelocity'] * np.sqrt(bath_temp / average_temp)
particles['yvelocity'] = particles['yvelocity'] * np.sqrt(bath_temp / average_temp)
return particles
22 changes: 14 additions & 8 deletions pylj/util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from __future__ import division
import numpy as np
import webbrowser
from pylj import comp
from pylj import md, mc
try:
from pylj import comp as heavy
except ImportError:
print("WARNING, using slow force and energy calculations")
from pylj import pairwise as heavy



Expand All @@ -28,7 +33,6 @@ class System:
"""
def __init__(self, number_of_particles, temperature, box_length, init_conf='square', timestep_length=1e-14,
cut_off=15):
from pylj import mc, md
self.number_of_particles = number_of_particles
self.init_temp = temperature
if box_length <= 600:
Expand Down Expand Up @@ -98,16 +102,18 @@ def random(self):
self.particles['yposition'] = np.random.uniform(0, self.box_length, self.number_of_particles)

def compute_force(self):
"""Maps to the comp.compute_force function and allows for a cleaner interface.
"""Maps to the compute_force function in either the comp (if Cython is installed) or the pairwise module and
allows for a cleaner interface.
"""
self.particles, self.distances, self.forces, self.energies = comp.compute_forces(self.particles,
self.particles, self.distances, self.forces, self.energies = heavy.compute_forces(self.particles,
self.box_length,
self.cut_off)

def compute_energy(self):
"""Maps to the comp.compute_energy function and allows for a cleaner interface.
"""Maps to the compute_energy function in either the comp (if Cython is installed) or the pairwise module
and allows for a cleaner interface.
"""
self.particles, self.distances, self.energies = comp.compute_energy(self.particles,
self.particles, self.distances, self.energies = heavy.compute_energy(self.particles,
self.box_length,
self.cut_off)

Expand All @@ -127,14 +133,14 @@ def md_sample(self):
md.sample(self.particles, self.box_length, self.initial_particles, self)

def heat_bath(self, bath_temperature):
"""Maps to the comp.heat_bath function.
"""Maps to the heat_bath function in either the comp (if Cython is installed) or the pairwise modules.
Parameters
----------
target_temperature: float
The target temperature for the simulation.
"""
self.particles = comp.heat_bath(self.particles, self.temperature_sample, bath_temperature)
self.particles = heavy.heat_bath(self.particles, self.temperature_sample, bath_temperature)

def mc_sample(self, energy):
"""Maps to the mc.sample function.
Expand Down

0 comments on commit b01fc10

Please sign in to comment.