Interactive online version: .

# Point Particles: Basic system initialization¶

Note: mBuild expects all distance units to be in nanometers.

This tutorial focuses on the usage of basic system initialization operations, as applied to simple point particle systems (i.e., generic Lennard-Jones particles rather than specific atoms).

The code below defines several point particles in a cubic arrangement. Note, the color and radius associated with a Particle name can be set and passed to the visualize command. Colors are passed in hex format (see http://www.color-hex.com/color/bfbfbf).



import mbuild as mb

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
lj_particle1 = mb.Particle(name='LJ', pos=[0, 0, 0])

lj_particle2 = mb.Particle(name='LJ', pos=[1, 0, 0])

lj_particle3 = mb.Particle(name='LJ', pos=[0, 1, 0])

lj_particle4 = mb.Particle(name='LJ', pos=[0, 0, 1])

lj_particle5 = mb.Particle(name='LJ', pos=[1, 0, 1])

lj_particle6 = mb.Particle(name='LJ', pos=[1, 1, 0])

lj_particle7 = mb.Particle(name='LJ', pos=[0, 1, 1])

lj_particle8 = mb.Particle(name='LJ', pos=[1, 1, 1])

monoLJ = MonoLJ()
monoLJ.visualize()


While this would work for defining a single molecule or very small system, this would not be efficient for large systems. Instead, the clone and translate operator can be used to facilitate automation. Below, we simply define a single prototype particle (lj_proto), which we then copy and translate about the system.

Note, mBuild provides two different translate operations, “translate” and “translate_to”. “translate” moves a particle by adding the vector the original position, whereas “translate_to” move a particle to the specified location in space. Note, “translate_to” maintains the internal spatial relationships of a collection of particles by first shifting the center of mass of the collection of particles to the origin, then translating to the specified location. Since the lj_proto particle in this example starts at the origin, these two commands produce identical behavior.



import mbuild as mb

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

for i in range(0,2):
for j in range(0,2):
for k in range(0,2):
lj_particle = mb.clone(lj_proto)
pos = [i,j,k]
lj_particle.translate(pos)

monoLJ = MonoLJ()
monoLJ.visualize()


To simplify this process, mBuild provides several build-in patterning tools, where for example, Grid3DPattern can be used to perform this same operation. Grid3DPattern generates a set of points, from 0 to 1, which get stored in the variable “pattern”. We need only loop over the points in pattern, cloning, translating, and adding to the system. Note, because Grid3DPattern defines points between 0 and 1, they must be scaled based on the desired system size, i.e., pattern.scale(2).



import mbuild as mb

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern = mb.Grid3DPattern(2, 2, 2)
pattern.scale(2)

for pos in pattern:
lj_particle = mb.clone(lj_proto)
lj_particle.translate(pos)

monoLJ = MonoLJ()
monoLJ.visualize()


Larger systems can therefore be easily generated by toggling the values given to Grid3DPattern. Other patterns can also be generated using the same basic code, such as a 2D grid pattern:



import mbuild as mb

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern = mb.Grid2DPattern(5, 5)
pattern.scale(5)

for pos in pattern:
lj_particle = mb.clone(lj_proto)
lj_particle.translate(pos)

monoLJ = MonoLJ()
monoLJ.visualize()


Points on a sphere can be generated using SpherePattern. Points on a disk using DisKPattern, etc.

Note to show both simultaneously, we shift the x-coordinate of Particles in the sphere by -1 (i.e., pos[0]-=1.0) and +1 for the disk (i.e, pos[0]+=1.0).



import mbuild as mb

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern_sphere = mb.SpherePattern(200)
pattern_sphere.scale(0.5)

for pos in pattern_sphere:
lj_particle = mb.clone(lj_proto)
pos[0]-=1.0
lj_particle.translate(pos)

pattern_disk = mb.DiskPattern(200)
pattern_disk.scale(0.5)
for pos in pattern_disk:
lj_particle = mb.clone(lj_proto)
pos[0]+=1.0
lj_particle.translate(pos)

monoLJ = MonoLJ()
monoLJ.visualize()


We can also take advantage of the hierachical nature of mBuild to accomplish the same task more cleanly. Below we create a component that corresponds to the sphere (class SphereLJ), and one that corresponds to the disk (class DiskLJ), and then instantiate and shift each of these individually in the MonoLJ component.



import mbuild as mb

class SphereLJ(mb.Compound):
def __init__(self):
super(SphereLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern_sphere = mb.SpherePattern(200)
pattern_sphere.scale(0.5)

for pos in pattern_sphere:
lj_particle = mb.clone(lj_proto)
lj_particle.translate(pos)

class DiskLJ(mb.Compound):
def __init__(self):
super(DiskLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern_disk = mb.DiskPattern(200)
pattern_disk.scale(0.5)
for pos in pattern_disk:
lj_particle = mb.clone(lj_proto)
lj_particle.translate(pos)

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()

sphere = SphereLJ();
pos=[-1, 0, 0]
sphere.translate(pos)

disk = DiskLJ();
pos=[1, 0, 0]
disk.translate(pos)

monoLJ = MonoLJ()
monoLJ.visualize()


Again, since mBuild is hierarchical, the pattern functions can be used to generate large systems of any arbitary component. For example, we can replicate the SphereLJ component on a regular array.



import mbuild as mb

class SphereLJ(mb.Compound):
def __init__(self):
super(SphereLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern_sphere = mb.SpherePattern(13)
pattern_sphere.scale(0.1)

for pos in pattern_sphere:
lj_particle = mb.clone(lj_proto)
lj_particle.translate(pos)
class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
sphere = SphereLJ();

pattern = mb.Grid3DPattern(3, 3, 3)
pattern.scale(2)

for pos in pattern:
lj_sphere = mb.clone(sphere)
lj_sphere.translate_to(pos)
#shift the particle so the center of mass
#of the system is at the origin
lj_sphere.translate([-5,-5,-5])

monoLJ = MonoLJ()
monoLJ.visualize()


Several functions exist for rotating compounds. For example, the spin command allows a compound to be rotated, in place, about a specific axis (i.e., it considers the origin for the rotation to lie at the compound’s center of mass).



import mbuild as mb
import random
from numpy import pi

class CubeLJ(mb.Compound):
def __init__(self):
super(CubeLJ, self).__init__()
lj_proto = mb.Particle(name='LJ', pos=[0, 0, 0])

pattern = mb.Grid3DPattern(2, 2, 2)
pattern.scale(0.2)

for pos in pattern:
lj_particle = mb.clone(lj_proto)
lj_particle.translate(pos)

class MonoLJ(mb.Compound):
def __init__(self):
super(MonoLJ, self).__init__()
cube_proto = CubeLJ();

pattern = mb.Grid3DPattern(3, 3, 3)
pattern.scale(2)
rnd = random.Random()
rnd.seed(123)

for pos in pattern:
lj_cube = mb.clone(cube_proto)
lj_cube.translate_to(pos)
#shift the particle so the center of mass
#of the system is at the origin
lj_cube.translate([-5,-5,-5])
lj_cube.spin( rnd.uniform(0, 2 * pi), [1, 0, 0])
lj_cube.spin(rnd.uniform(0, 2 * pi), [0, 1, 0])
lj_cube.spin(rnd.uniform(0, 2 * pi), [0, 0, 1])

monoLJ = MonoLJ()
monoLJ.visualize()


Configurations can be dumped to file using the save command; this takes advantage of MDTraj and supports a range of file formats (see http://MDTraj.org).



#save as xyz file
monoLJ.save('output.xyz')
#save as mol2
monoLJ.save('output.mol2')