Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pylj class #64

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 181 additions & 112 deletions pylj/forcefields.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,133 +2,166 @@
from numba import njit


#Jit tag here had to be removed
def lennard_jones(dr, constants, force=False):
class lennard_jones(object):
r"""Calculate the energy or force for a pair of particles using the
Lennard-Jones (A/B variant) forcefield.

.. math::
E = \frac{A}{dr^{12}} - \frac{B}{dr^6}

.. math::
f = \frac{12A}{dr^{13}} - \frac{6B}{dr^7}

Parameters
----------
dr: float, array_like
The distances between the all pairs of particles.
constants: float, array_like
An array of length two consisting of the A and B parameters for the
12-6 Lennard-Jones function
force: bool (optional)
If true, the negative first derivative will be found.

Returns
-------
float: array_like
The potential energy or force between the particles.
"""
def __init__(self, dr, constants):
self.dr = dr
self.a = constants[0]
self.b = constants[1]
self.energy = self.update_energy()
self.force = self.update_force()

def update_energy(self):
r"""Calculate the energy for a pair of particles using the
Lennard-Jones (A/B variant) forcefield.

.. math::
E = \frac{A}{dr^{12}} - \frac{B}{dr^6}

Returns
-------
float: array_like
The potential energy between the particles.
"""
self.energy = self.a * np.power(self.dr, -12) - (self.b * np.power(self.dr, -6))
return self.energy

def update_force(self):
r"""Calculate the force for a pair of particles using the
Lennard-Jones (A/B variant) forcefield.

.. math::
f = \frac{12A}{dr^{13}} - \frac{6B}{dr^7}

if force:
return 12 * constants[0] * np.power(dr, -13) - (
6 * constants[1] * np.power(dr, -7))
Returns
-------
float: array_like
The force between the particles.
"""
self.force = 12 * self.a * np.power(self.dr, -13) - (6 * self.b * np.power(self.dr, -7))
return self.force

else:
return constants[0] * np.power(dr, -12) - (
constants[1] * np.power(dr, -6))


#Jit tag here had to be removed
def lennard_jones_sigma_epsilon(dr, constants, force=False):
class lennard_jones_sigma_epsilon(object):
r"""Calculate the energy or force for a pair of particles using the
Lennard-Jones (sigma/epsilon variant) forcefield.

.. math::
E = \frac{4e*a^{12}}{dr^{12}} - \frac{4e*a^{6}}{dr^6}

.. math::
f = \frac{48e*a^{12}}{dr^{13}} - \frac{24e*a^{6}}{dr^7}

Parameters
----------
dr: float, array_like
The distances between the all pairs of particles.
constants: float, array_like
An array of length two consisting of the sigma (a) and epsilon (e)
parameters for the 12-6 Lennard-Jones function
force: bool (optional)
If true, the negative first derivative will be found.

Returns
-------
float: array_like
The potential energy or force between the particles.
"""

if force:
return 48 * constants[1] * np.power(constants[0], 12) * np.power(
dr, -13) - (24 * constants[1] * np.power(
constants[0], 6) * np.power(dr, -7))
else:
return 4 * constants[1] * np.power(constants[0], 12) * np.power(dr, -12) - (
4 * constants[1] * np.power(constants[0], 6) * np.power(dr, -6))


#Jit tag here had to be removed
def buckingham(dr, constants, force=False):
def __init__(self, dr, constants):
self.dr = dr
self.sigma = constants[0]
self.epsilon = constants[1]
self.energy = self.update_energy()
self.force = self.update_force()

def update_energy(self):
r"""Calculate the energy for a pair of particles using the
Lennard-Jones (sigma/epsilon variant) forcefield.

.. math::
E = \frac{4e*a^{12}}{dr^{12}} - \frac{4e*a^{6}}{dr^6}

Returns
-------
float: array_like
The potential energy between the particles.
"""
self.energy = 4 * self.epsilon * np.power(self.sigma, 12) * np.power(self.dr, -12) - (
4 * self.epsilon * np.power(self.sigma, 6) * np.power(self.dr, -6))
return self.energy

def update_force(self):
r"""Calculate the force for a pair of particles using the
Lennard-Jones (sigma/epsilon variant) forcefield.

.. math::
f = \frac{48e*a^{12}}{dr^{13}} - \frac{24e*a^{6}}{dr^7}

Returns
-------
float: array_like
The force between the particles.
"""
self.force = 48 * self.epsilon * np.power(self.sigma, 12) * np.power(
self.dr, -13) - (24 * self.epsilon * np.power(self.sigma, 6) * np.power(self.dr, -7))
return self.force



class buckingham(object):
r""" Calculate the energy or force for a pair of particles using the
Buckingham forcefield.

.. math::
E = Ae^{(-Bdr)} - \frac{C}{dr^6}

.. math::
f = ABe^{(-Bdr)} - \frac{6C}{dr^7}

Parameters
----------
dr: float, array_like
The distances between all the pairs of particles.
constants: float, array_like
An array of length three consisting of the A, B and C parameters for
the Buckingham function.
force: bool (optional)
If true, the negative first derivative will be found.

Returns
-------
float: array_like
The potential energy or force between the particles.
"""
if force:
return constants[0] * constants[1] * np.exp(
- np.multiply(constants[1], dr)) - 6 * constants[2] / np.power(
dr, 7)
else:
return constants[0] * np.exp(
- np.multiply(constants[1], dr)) - constants[2] / np.power(dr, 6)
def __init__(self, dr, constants):
self.dr = dr
self.a = constants[0]
self.b = constants[1]
self.c = constants[2]
self.energy = self.update_energy()
self.force = self.update_force()

def update_energy(self):
r"""Calculate the energy for a pair of particles using the
Buckingham forcefield.

.. math::
E = Ae^{(-Bdr)} - \frac{C}{dr^6}

Returns
-------
float: array_like
The potential energy between the particles.
"""
self.energy = self.a * np.exp(- np.multiply(self.b, self.dr)) - self.c / np.power(self.dr, 6)
return self.energy

def update_force(self):
r"""Calculate the force for a pair of particles using the
Buckingham forcefield.

.. math::
f = ABe^{(-Bdr)} - \frac{6C}{dr^7}

Returns
-------
float: array_like
The force between the particles.
"""
self.force = self.a * self.b * np.exp(- np.multiply(self.b, self.dr)) - 6 * self.c / np.power(self.dr, 7)
return self.force



def square_well(dr, constants, max_val=np.inf, force=False):
class square_well(object):
r'''Calculate the energy or force for a pair of particles using a
square well model.

.. math::
E = {
if dr < sigma:
E = max_val
elif sigma <= dr < lambda * sigma:
E = -epsilon
elif r >= lambda * sigma:
E = 0
}
.. math::
f = {
if sigma <= dr < lambda * sigma:
f = inf
else:
f = 0
}
Parameters
----------
dr: float, array_like
Expand All @@ -138,34 +171,70 @@ def square_well(dr, constants, max_val=np.inf, force=False):
parameters for the square well model.
max_val: int (optional)
Upper bound for values in square well - replaces usual infinite values
force: bool (optional)
If true, the negative first derivative will be found.

Returns
-------
float: array_like
The potential energy between the particles.
'''
if not isinstance(dr, np.ndarray):
if isinstance(dr, list):
dr = np.array(dr, dtype='float')
elif isinstance(dr, float):
dr = np.array([dr], dtype='float')

if force:
raise ValueError("Force is infinite at sigma <= dr < lambda * sigma")

else:
E = np.zeros_like(dr)
E[np.where(dr < constants[0])] = max_val
E[np.where(dr >= constants[2] * constants[1])] = 0

# apply mask for sigma <= dr < lambda * sigma
a = constants[1] <= dr
b = dr < constants[2] * constants[1]
E[np.where(a & b)] = -constants[0]
def __init__(self, dr, constants, max_val=np.inf):

if not isinstance(dr, np.ndarray):
if isinstance(dr, list):
dr = np.array(dr, dtype='float')
elif isinstance(dr, float):
dr = np.array([dr], dtype='float')

self.dr = dr
self.epsilon = constants[0]
self.sigma = constants[1]
self.lamda = constants[2] #Spelling as lamda not lambda to avoid calling python lambda function
self.max_val = max_val
self.energy = self.update_energy()
self.force = 0

def update_energy(self):
r'''Calculate the energy for a pair of particles using a
square well model.

.. math::
E = {
if dr < sigma:
E = max_val
elif sigma <= dr < lambda * sigma:
E = -epsilon
elif r >= lambda * sigma:
E = 0
}

Returns
-------
float: array_like
The potential energy between the particles.
'''
E = np.zeros_like(self.dr)
E = np.zeros_like(self.dr)
E[np.where(self.dr < self.epsilon)] = self.max_val
E[np.where(self.dr >= self.lamda * self.sigma)] = 0

# apply mask for sigma <= self.dr < lambda * sigma
a = self.sigma <= self.dr
b = self.dr < self.lamda * self.sigma
E[np.where(a & b)] = -self.epsilon

if len(E) == 1:
return float(E[0])
self.energy = float(E[0])
else:
return np.array(E, dtype='float')
self.energy = np.array(E, dtype='float')

return self.energy

def update_force(self):
r'''The force of a pair of particles using a square well model is given by:

.. math::
f = {
if sigma <= dr < lambda * sigma:
f = inf
else:
f = 0
}

Therefore the force here will always be infinite, and therefore not possible to simulate
'''
raise ValueError("Force is infinite at sigma <= dr < lambda * sigma")
8 changes: 4 additions & 4 deletions pylj/pairwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def compute_force(particles, box_length, cut_off, constants, forcefield, mass):
distances, dx, dy = heavy.dist(
particles["xposition"], particles["yposition"], box_length
)
forces = forcefield(distances, constants, force=True)
energies = forcefield(distances, constants, force=False)
forces = forcefield(distances, constants).force
energies = forcefield(distances, constants).energy
forces[np.where(distances > cut_off)] = 0.0
energies[np.where(distances > cut_off)] = 0.0
particles = update_accelerations(particles, forces, mass_kg, dx, dy, distances)
Expand Down Expand Up @@ -211,7 +211,7 @@ def compute_energy(particles, box_length, cut_off, constants, forcefield):
distances, dx, dy = heavy.dist(
particles["xposition"], particles["yposition"], box_length
)
energies = forcefield(distances, constants, force=False)
energies = forcefield(distances, constants).energy
energies[np.where(distances > cut_off)] = 0.0
return distances, energies

Expand Down Expand Up @@ -248,7 +248,7 @@ def calculate_pressure(
distances, dx, dy = heavy.dist(
particles["xposition"], particles["yposition"], box_length
)
forces = forcefield(distances, constants, force=True)
forces = forcefield(distances, constants).force
forces[np.where(distances > cut_off)] = 0.0
pres = np.sum(forces * distances)
boltzmann_constant = 1.3806e-23 # joules / kelvin
Expand Down
Loading
Loading