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.
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.
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 |
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 |
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 |
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 |
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 |
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.
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 |
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).