Previous Section - LAMMPS WWW Site - LAMMPS Documentation - LAMMPS Commands - Next Section

8. Modifying & extending LAMMPS

LAMMPS is designed in a modular fashion so as to be easy to modify and extend with new functionality. In this section, changes and additions users can make are listed along with some minimal instructions. Realistically, the best way to add a new feature is to find a similar feature in LAMMPS and look at the corresponding source and header files to figure out what it does. You will need some knowledge of C++ to be able to understand the hi-level structure of LAMMPS and its class organization, but functions (class methods) that do actual computations are written in vanilla C-style code and operate on simple C-style data structures (vectors and arrays).

The new features described in this section require you to write a new C++ class (except for dump options, described below). This requires 2 files, one with source code (*.cpp) and a header file (*.h). Their contents are briefly discussed below. Enabling LAMMPS to invoke the new class is as simple as adding two definition lines to the style_user.h file, in the same syntax as the existing LAMMPS features are defined in the style.h file.

The power of C++ and its object-orientation is that usually, all the code and variables needed to define the new feature are contained in the 2 files you write, and thus shouldn't make the rest of the code more complex or cause side-effect bugs.

Here is a concrete example. Suppose you write 2 files pair_foo.cpp and pair_foo.h that define a new class PairFoo that computes pairwise potentials described in the classic 1997 paper by Foo, et. al. If you wish to invoke those potentials in a LAMMPS input script with a command like

pair_style foo 0.1 3.5 

you simply need to put your 2 files in the LAMMPS src directory, add 2 lines to the style_user.h file, and re-make the code.

The first line added to style_user.h would be

PairStyle(foo,PairFoo) 

in the #ifdef PairClass section, where "foo" is the style keyword in the pair_style command, and PairFoo is the class name in your C++ files.

The 2nd line added to style_user.h would be

#include "pair_foo.h" 

in the #ifdef PairInclude section, where pair_foo.h is the name of your new include file.

When you re-make LAMMPS, your new pairwise potential becomes part of the executable and can be invoked with a pair_style command like the example above. Arguments like 0.1 and 3.5 can be defined and processed by your new class.

Note that if you are using Makefile.list instead of Makefile to build LAMMPS, you will need to add the names of your new .cpp and .h file to Makefile.list.

Here is a list of the kinds of new features that can be added in this way:

As illustrated by the pairwise example, these options are referred to in the LAMMPS documentation as the "style" of a particular command.

The instructions below for each category will list the header file for the parent class that these styles are sub-classes of. Public variables in that file are ones used and set by the sub-classes which are also used by the parent class. Sometimes they are also used by the rest of LAMMPS. Virtual functions in the header file which are set = 0 are ones you must define in your new class to give it the functionality LAMMPS expects. Virtual functions that are not set to 0 are functions you can optionally define.

Here are some additional guidelines for modifying LAMMPS and adding new functionality:

Think about whether what you want to do would be better as a pre- or post-processing step. Many computations are more easily and more quickly done that way.

Don't do anything within the timestepping of a run that isn't parallel. E.g. don't accumulate a bunch of data on a single processor and analyze it. You run the risk of seriously degrading the parallel efficiency.

If your new feature reads arguments or writes output, make sure you follow the unit conventions discussed by the units command.

If you add something you think is truly useful and doesn't impact LAMMPS performance when it isn't used, send me an email. We might be interested in adding it to the LAMMPS distribution.


Pairwise potentials

All classes that compute pairwise interactions are sub-classes of the Pair class. See the pair.h file for a list of methods this class defines.

Pair_lj_cut.cpp and pair_lj_cut.h are the simplest example of a Pair class. They implement the lj/cut style of the pair_style command.

Here is a brief description of the class methods in pair.h:

compute the workhorse routine that computes the pairwise interactions
settings reads the input script line with any arguments you define
coeff set coefficients for one i,j type pair
init_one perform initialization for one i,j type pair
write & read_restart write/read i,j pair coeffs to restart files
write & read_restart_settings write/read global settings to restart files
single force and energy of a single pairwise interaction between 2 atoms
compute_inner/middle/outer versions of compute used by rRESPA

The inner/middle/outer routines are optional. Only a few of the pairwise potentials use these in conjunction with rRESPA as set by the run_style command.


Bond, angle, dihedral, improper potentials

All classes that compute molecular interactions are sub-classes of the Bond, Angle, Dihedral, and Improper classes. See the bond.h, angle.h, dihedral.h, and improper.h file for a list of methods these classes defines.

Bond_harmonic.cpp and bond_harmonic.h are the simplest example of a Bond class. Ditto for the harmonic forms of the angle, dihedral, and improper style commands. The bond_harmonic files implement the harmonic style of the bond_style command.

Here is a brief description of the class methods in bond.h, angle.h, etc:

compute the workhorse routine that computes the molecular interactions
coeff set coefficients for one bond type
equilibrium_distance length of bond, used by SHAKE
write & read_restart writes/reads coeffs to restart files
single force and energy of a single bond

Dump options

Unlike the other styles described on this page, new dump features can be added without writing a new class. The dump command has a custom style that allows you to specify what information should be dumped with each atom. If the attribute you want to dump is not in the list, or if you define a new atom style with new attributes (e.g. atoms that store their own energy), here is how to dump it out in a snapshot file, via additions you make to the dump_custom.cpp and dump_custom.h file.

The dump_custom.cpp file has lines like the following one for FX. Add a new keyword to the list.

#define FX 15 

In the dump_custom constructor, add 4 lines that define the attribute name (e.g. "fx"), vnamei, vtypei, and pack_choicei for your new option.

Add a new pack method to the DumpCustom class that stores your new atom quantity in the dump buffer, similar to all the other pack_* methods. The name of this new method is what you assigned to pack_choicei. You can do a modest amount of computation in this routine to write out precisely what you want - e.g. see the pack_xs routine, which scales the atom's x coordinate.

Add a prototype for your new method to the dump_custom.h file, like the other pack_* methods.

If desired, a dump custom option can also compute more complicated quantities by invoking a fix that computed quantities at the end of a timestep (should be the same timestep the dump is invoked on). See the ENERGY, CENTRO, and stress options (SXX, SYY, etc) in dump_custom.cpp for examples.

When you re-make LAMMPS, your new option should now be useable via the dump custom command.

Similar to the other styles in this section, you can also create new dump styles (like atom, velocity, bond) as new classes, if modifying the dump custom command is not sufficient for your needs. These are sub-classes of the Dump class. See the dump.h file for a list of methods these classes defines.

Dump_velocity.cpp and dump_velocity.h are the simplest example of a Dump class. They implement the velocity style of the dump command.

Here is a brief description of the class methods in dump.h:

write_header writes the header section of each snapshot
count counts the number of snapshot lines to be written out
pack packs atom information into the dump buffer
write_data writes out a buffer in the dump format

Thermodynamic output options

All classes that compute and print thermodynamic information to the screen and log file are sub-classes of the Thermo class. See the thermo.h file for a list of methods these classes defines.

Thermo_one.cpp and thermo_one.h are the simplest example of a Thermo class. They implement the one style of the thermo command.

Here is a brief description of the class methods in thermo.h:

header writes the header to the thermodynamic output
compute computes current thermodynamics of the system

Temperature computation options

All classes that compute the temperature of the system are sub-classes of the Temperature class. See the temperature.h file for a list of methods these classes defines. Temperatures are computed by LAMMPS when velocities are set, when thermodynamics are computed, and when temperature is controlled by various thermostats like the fix nvt of fix langevin commands.

Temp_full.cpp and temp_full.h are the simplest example of a Temperature class. They implement the full style of the temperature command.

Here is a brief description of the class methods in temperature.h:

init setup the temperature computation
compute compute and return temperature

Region geometry options

All classes that define geometric regions are sub-classes of the Region class. See the region.h file for a list of methods these classes defines. Regions are used elsewhere in LAMMPS to group atoms, delete atoms to create a void, insert atoms in a specified region, etc.

Region_sphere.cpp and region_sphere.h are the simplest example of a Region class. They implement the sphere style of the region command.

Here is a brief description of the single class method required:

match determine whether a point is in the region

Fix options

In LAMMPS, a "fix" is any operation that is computed during timestepping that alters some property of the system. Essentially everything that happens during a simulation besides force computation, neighbor list manipulation, and output, is a "fix". This includes time integration (update of velocity and coordinates), force constraints (SHAKE or walls), and diagnostics (compute a diffusion coefficient). See the fix.h file for a list of methods these classes defines.

There are dozens of fix options in LAMMPS; choose one as a template that is similar to what you want to implement. They can be as simple as zeroing out forces (see fix enforce2d which corresponds to the enforce2d style) or as complicated as applying SHAKE constraints on bonds and angles (see fix shake which corresponds to the shake style) which involves many extra computations.

Here is a brief description of the class methods in fix.h:

setmask determines when the fix is called during the timestep
init initialization before a run
setup called immediately before the 1st timestep
initial_integrate called at very beginning of each timestep
pre_exchange called before atom exchange on re-neighboring steps
pre_neighbor called before neighbor list build
post_force called after pair & molecular forces are computed
final_integrate called at end of each timestep
end_of_step called at very end of timestep
write_restart dumps fix info to restart file
restart uses info from restart file to re-initialize the fix
grow_arrays allocate memory for atom-based arrays used by fix
copy_arrays copy atom info when an atom migrates to a new processor
memory_usage report memory used by fix
pack_exchange store atom's data in a buffer
unpack_exchange retrieve atom's data from a buffer
pack_restart store atom's data for writing to restart file
unpack_restart retrieve atom's data from a restart file buffer
size_restart size of atom's data
maxsize_restart max size of atom's data
initial_integrate_respa same as initial_integrate, but for rRESPA
post_force_respa same as post_force, but for rRESPA
final_integrate_respa same as final_integrate, but for rRESPA
pack_comm pack a buffer to communicate a per-atom quantity
unpack_comm unpack a buffer to communicate a per-atom quantity
pack_reverse_comm pack a buffer to reverse communicate a per-atom quantity
unpack_reverse_comm unpack a buffer to reverse communicate a per-atom quantity

Typically, only a small fraction of these methods are defined for a particular fix. Setmask is mandatory, as it determines when the fix will be invoked during the timestep. Fixes that perform time integration (nve, nvt, npt) implement initial_integrate and final_integrate to perform velocity Verlet updates. Fixes that constrain forces implement post_force. Fixes that perform diagnostics typically implement end_of_step.

If the fix needs to store information for each atom that persists from timestep to timestep, it can manage that memory and migrate it with the atoms as they move from processors to processor by implementing the grow_arrays, copy_arrays, pack_exchange, and unpack_exchange methods. Similary, the pack_restart and unpack_restart methods can be implemented to store information about the fix in restart files. If you wish a integrator or force constraint fix to work with rRESPA (see the run_style command), the initial_integrate, post_force_integrate, and final_integrate_respa methods can be implemented.


Atom options

All classes that define an atom style are sub-classes of the Atom class. See the atom.h file for a list of methods these classes defines. The atom style determines what quantities are associated with an atom in a LAMMPS simulation. If one of the existing atom styles does not define all the arrays you need to store with an atom, then a new atom class can be created.

Atom_atomic.cpp and atom_atomic.h are the simplest example of an Atom class. They implement the atomic style of the atom_style command.

Here is a brief description of the class methods in atom.h:

copy copy info for one atom to another atom's array location
pack_comm store an atom's info in a buffer communicated every timestep
unpack_comm retrieve an atom's info from the buffer
pack_reverse store an atom's info in a buffer communicating partial forces
unpack_reverse retrieve an atom's info from the buffer
pack_border store an atom's info in a buffer communicated on neighbor re-builds
unpack_border retrieve an atom's info from the buffer
pack_exchange store all an atom's info to migrate to another processor
unpack_exchange retrieve an atom's info from the buffer

There are also several methods in atom.cpp you will need to augment with information about your new atom class, following the patterns of the other atom styles. These routines are so similar for all classes, that it was simpler to just have one master routine for all classes.

constructor create style variable and atom array ptrs to NULL
destructor free memory for atom arrays
set_style set style variable
check_style check for pure style vs hybrid style
style2arg convert style variables to keywords
grow re-allocate atom arrays to longer lengths
unpack_data parse atom lines from data file
create_one create an individual atom of this style
size_restart number of restart quantities associated with proc's atoms
pack_restart pack atom quantities into a buffer
unpack_restart unpack atom quantities from a buffer
memory_usage memory allocated by atom arrays

New Top-level Commands

It is possible to add a new command to a LAMMPS input script as opposed to adding a new style to an existing command (atom_style, pair_style, fix, etc). For example the create_atoms, read_data, velocity, and run commands are all top-level LAMMPS commands that are listed in the Command section of style.h. When such a command is encountered in the LAMMPS input script, the topmost level of LAMMPS (lammps.cpp) simply creates a class with the corresponding name, invokes the "command" method of the class, and passes it the arguments from the input script. The command method can perform whatever operations it wishes on the LAMMPS data structures.

Thus to add a new command, you simply need to add a *.cpp and *.h file containing a single class:

command operations performed by the new command

Of course, the new class can define other methods and variables that it uses internally.


(Foo) Foo, Morefoo, and Maxfoo, J of Classic Potentials, 75, 345 (1997).