Potentials
One of the main goals of Tissue Forge is to enable users to rapidly develop and explore empirical or phenomenological models of active and biological matter in the 100nm to multiple cm range. Supporting modeling and simulation in these ranges requires a good deal of flexibility to create and calibrate potential functions to model material rheology and particle interactions.
Tissue Forge provides a wide range of potentials in the Potential
class.
Any of the built-in potential functions
can be created as objects in a simulation using a static method on the
Potential
class, which can be bound to pairs and
groups of particles to implement models of interactions.
Creating, Plotting and Exploring Potentials
Potential
objects are created simply by calling one of the
static methods on the Potential
class. In Python, Potential
objects conveniently have a plot
method that displays a
graph of the potential energy in a matplotlib
plot. For example, while working
with the built-in Generalized Lennard-Jones potential,
import tissue_forge as tf
pot = tf.Potential.glj(1)
pot.plot(potential=True, force=False, ymin=-1, ymax=1)
results in
A Potential
instance can also be created by adding two existing
instances. Such operations can be arbitrarily performed to construct complicated
potentials consisting of multiple constituent potentials,
pot_charged = tf.Potential.coulomb(q=1)
pot_fluid = tf.Potential.dpd(alpha=0.3, gamma=1, sigma=1, cutoff=0.6)
pot_charged_fluid = pot_charged + pot_fluid
Note
Changes to constituent potentials during simulation are reflected in potentials that have been constructed from them using summation operations.
Tissue Forge also supports creating custom potentials with the Potential
method
custom
. A custom Potential
requires the domain
of the Potential
and, at minimum, a function that takes a float as argument and
returns the value of the Potential
at the argument value. Tissue Forge constructs
an interpolation of a potential function using functions that return the value of the
Potential
, its first derivative, and its sixth derivative. When a function is
not provided for either derivative, the derivative is approximated using finite difference,
pot_custom = tf.Potential.custom(min=0.0, max=2.0,
f=lambda r: (r-1.0) ** 6.0, # Potential function
fp=lambda r: 6.0 * (r-1.0) ** 5.0, # First derivative
f6p=lambda r: 720.0) # Sixth derivative
Potentials for angle and
dihedral bonds can be created by passing
Potential.Flags.angle.value
and Potential.Flags.dihedral.value
, respectively
(POTENTIAL_ANGLE
and POTENTIAL_DIHEDRAL
in C++, respectively), to
the keyword argument flags
. In both cases, the cosine of the angle of an angle or
dihedral bond is passed as argument to the potential function,
pot_angle = tf.Potential.custom(min=-0.999, max=0.999,
f=lambda r: cos(2.0 * acos(r)),
flags=tf.Potential.Flags.angle.value)
Note
The cosine of angles is used when evaluating angle and dihedral bonds to improve
computational performance, but presents challenges to creating custom potentials in
that analytic expressions for derivatives of the potential function can be excessively
tedious to derive and implement. This issue motivates providing built-in support
for approximating derivatives using finite difference. However, providing functions
for the first and sixth derivative of a potential function is recommended whenever possible,
as is examining the quality of the generated interpolation of a potential function before
using it in a simulation using plot
.
Built-in Potentials
Presently, the following built-in potential functions are supported, with corresponding constructor method. For details on the parameters of each function, refer to the Tissue Forge API Reference.
12-6 Lennard-Jones:
Potential.lennard_jones_12_6
12-6 Lennard-Jones with shifted Coulomb:
Potential.lennard_jones_12_6_coulomb
Coulomb:
Potential.coulomb
Coulomb reciprocal potential:
Potential.coulombR
Dissipative particle dynamics:
Potential.dpd
Ewald (real-space):
Potential.ewald
Generalized Lennard-Jones:
Potential.glj
Harmonic:
Potential.harmonic
Harmonic angle:
Potential.harmonic_angle
Harmonic dihedral:
Potential.harmonic_dihedral
Cosine dihedral:
Potential.cosine_dihedral
Linear:
Potential.linear
Morse:
Potential.morse
Overlapping sphere:
Potential.overlapping_sphere
Power:
Potential.power
Well:
Potential.well
Shifted Potentials
Some potentials (e.g., morse
) provide default or optional
shifted forms. When a potential is shifted, the distance between two particles during
an interaction is shifted by the sum of radii of the two particles. For example, the two
following potentials produce the same potential, though only one uses shifting,
class PType(tf.ParticleTypeSpec):
radius = 0.1
ptype = PType.get()
pot_shifted = tf.Potential.morse(min=-ptype.radius * 2, max=2 - ptype.radius * 2, r0=0)
pot_noshift = tf.Potential.morse(min=0, max=2, r0=ptype.radius * 2, shifted=False)
Potential Details
Most potentials define a range of distances over which two particles interact, which Tissue Forge uses to construct an interpolation of the potential function for imposing forces on interacting particles. As such, interpolated potentials cannot be altered once they have been created, and so changing a potential during a simulation requires replacing the potential with an updated version of itself. For potentials that are bound to pairs of particles by type, performing binding replaces any potential that was previously bound to a pair of particle types. For updating bonded interactions, a bond can simply be destroyed and recreated with the updated potential. Furthermore, potentials that use interpolations are not defined outside of their prescribed range of distances. For the case of two particles that are separated by a distance greater than the maximum distance of a potential range, Tissue Forge simply ignores the potential (like the global cutoff distance). For the case of two particles that are separated by a distance less than the minimum distance of a potential range, the magnitude of the resulting force at the minimum distance of the potential range is applied.