Skip to content

Commit

Permalink
Merge pull request #65 from maximillian-dolan/master
Browse files Browse the repository at this point in the history
  • Loading branch information
arm61 authored Jun 17, 2024
2 parents 04d3ef9 + f5061e4 commit d4395eb
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 191 deletions.
312 changes: 197 additions & 115 deletions pylj/forcefields.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,170 +2,252 @@
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, constants):
self.a = constants[0]
self.b = constants[1]

if force:
return 12 * constants[0] * np.power(dr, -13) - (
6 * constants[1] * np.power(dr, -7))
def energy(self, dr ):
r"""Calculate the energy for a pair of particles using the
Lennard-Jones (A/B variant) forcefield.
else:
return constants[0] * np.power(dr, -12) - (
constants[1] * np.power(dr, -6))
.. math::
E = \frac{A}{dr^{12}} - \frac{B}{dr^6}
Attributes:
----------
dr (float): The distance between particles.
#Jit tag here had to be removed
def lennard_jones_sigma_epsilon(dr, constants, force=False):
Returns
-------
float: array_like
The potential energy between the particles.
"""
self.energy = self.a * np.power(dr, -12) - (self.b * np.power(dr, -6))
return self.energy

def force(self, dr):
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}
Attributes:
----------
dr (float): The distance between particles.
Returns
-------
float: array_like
The force between the particles.
"""
self.force = 12 * self.a * np.power(dr, -13) - (6 * self.b * np.power(dr, -7))
return self.force



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, constants):
self.sigma = constants[0]
self.epsilon = constants[1]

def energy(self, dr):
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}
Attributes:
----------
dr (float): The distance between particles.
Returns
-------
float: array_like
The potential energy between the particles.
"""
self.energy = 4 * self.epsilon * np.power(self.sigma, 12) * np.power(dr, -12) - (
4 * self.epsilon * np.power(self.sigma, 6) * np.power(dr, -6))
return self.energy

def force(self, dr):
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}
Attributes:
----------
dr (float): The distance between particles.
Returns
-------
float: array_like
The force between the particles.
"""
self.force = 48 * self.epsilon * np.power(self.sigma, 12) * np.power(
dr, -13) - (24 * self.epsilon * np.power(self.sigma, 6) * np.power(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 square_well(dr, constants, max_val=np.inf, force=False):
def __init__(self, constants):
self.a = constants[0]
self.b = constants[1]
self.c = constants[2]

def energy(self, dr):
r"""Calculate the energy for a pair of particles using the
Buckingham forcefield.
.. math::
E = Ae^{(-Bdr)} - \frac{C}{dr^6}
Attributes:
----------
dr (float): The distance between particles.
Returns
-------
float: array_like
The potential energy between the particles.
"""
self.energy = self.a * np.exp(- np.multiply(self.b, dr)) - self.c / np.power(dr, 6)
return self.energy

def force(self, dr):
r"""Calculate the force for a pair of particles using the
Buckingham forcefield.
.. math::
f = ABe^{(-Bdr)} - \frac{6C}{dr^7}
Attributes:
----------
dr (float): The distance between particles.
Returns
-------
float: array_like
The force between the particles.
"""
self.force = self.a * self.b * np.exp(- np.multiply(self.b, dr)) - 6 * self.c / np.power(dr, 7)
return self.force



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
The distances between all the pairs of particles.
constants: float, array_like
An array of length three consisting of the epsilon, sigma, and lambda
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")
def __init__(self, constants, max_val=np.inf):

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

def energy(self, dr):
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
}
Attributes:
----------
dr (float): The distance between particles.
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')

else:
E = np.zeros_like(dr)
E[np.where(dr < constants[0])] = max_val
E[np.where(dr >= constants[2] * constants[1])] = 0
E = np.zeros_like(dr)
E[np.where(dr < self.epsilon)] = self.max_val
E[np.where(dr >= self.lamda * self.sigma)] = 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]
a = self.sigma <= dr
b = 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:
self.energy = np.array(E, dtype='float')

return self.energy

def 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:
return np.array(E, dtype='float')
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")
Loading

0 comments on commit d4395eb

Please sign in to comment.