forked from lijiext/lammps
476 lines
20 KiB
Plaintext
476 lines
20 KiB
Plaintext
|
"Previous Section"_Section_tools.html - "LAMMPS WWW Site"_lws -
|
||
|
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
|
||
|
Section"_Section_errors.html :c
|
||
|
|
||
|
:link(lws,http://lammps.sandia.gov)
|
||
|
:link(ld,Manual.html)
|
||
|
:link(lc,Section_commands.html#comm)
|
||
|
|
||
|
:line
|
||
|
|
||
|
8. Modifying & extending LAMMPS :h3
|
||
|
|
||
|
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).
|
||
|
|
||
|
Most of the new features described in this section require you to
|
||
|
write a new C++ class (except for dump, thermo, and variable options,
|
||
|
described below, where you can make small edits to existing files).
|
||
|
Creating a new class requires 2 files, a source code file (*.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 classes 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"_#Foo 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 :pre
|
||
|
|
||
|
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) :pre
|
||
|
|
||
|
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" :pre
|
||
|
|
||
|
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 explicitly 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. The dump and thermo options do not typically require new styles;
|
||
|
LAMMPS can simply be recompiled after new code is added to
|
||
|
dump_custom.cpp or thermo_custom.cpp.
|
||
|
|
||
|
"Pairwise potentials"_#pair
|
||
|
"Bond, angle, dihedral, improper potentials"_#bond
|
||
|
"Dump options"_#dump
|
||
|
"Thermodynamic output options"_#thermo
|
||
|
"Temperature computation options"_#temp
|
||
|
"Region geometry options"_#region
|
||
|
"Fix options"_#fix which include integrators, \
|
||
|
temperature and pressure control, force constraints, \
|
||
|
boundary conditions, diagnostic output, etc
|
||
|
"Atom options"_#atom
|
||
|
"Variable options"_#variable
|
||
|
"New top-level commands"_#command :ul
|
||
|
|
||
|
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"_units.html
|
||
|
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"_mail. We
|
||
|
might be interested in adding it to the LAMMPS distribution.
|
||
|
|
||
|
:link(mail,mailto:sjplimp@sandia.gov)
|
||
|
|
||
|
:line
|
||
|
|
||
|
Pairwise potentials :link(pair),h4
|
||
|
|
||
|
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"_pair_style.html 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 :tb(s=:)
|
||
|
|
||
|
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"_run_style.html command.
|
||
|
|
||
|
:line
|
||
|
|
||
|
Bond, angle, dihedral, improper potentials :link(bond),h4
|
||
|
|
||
|
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"_bond_style.html 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 :tb(s=:)
|
||
|
|
||
|
:line
|
||
|
|
||
|
Dump options :link(dump),h4
|
||
|
|
||
|
There are several classes that print dump files (snapshots of atoms)
|
||
|
that are sub-classes of the Dump class. These include the
|
||
|
dump_atom.cpp, dump_bond.cpp, and dump_custom.cpp files.
|
||
|
|
||
|
New dump classes can be added, but it is typically simpler to modify
|
||
|
the DumpCustom class contained in the dump_custom.cpp file. See the
|
||
|
"dump"_dump.html command and its {custom} style for a list of what
|
||
|
atom information can already be dumped by DumpCustom. If the
|
||
|
attribute you want to dump is not in the list, or if you define a "new
|
||
|
atom style"_#atom with new attributes (e.g. atoms that store their own
|
||
|
magnetic moment), here is how to dump it out in a snapshot file:
|
||
|
|
||
|
Search the dump_custom.cpp and dump_custom.h files for the word
|
||
|
"customize". It appears in roughly half a dozen locations. In each
|
||
|
of the locations you can add a bit of code that will extend the
|
||
|
DumpCustom class to enable it to dump a new quantity. E.g. you will
|
||
|
add a keyword, add an if test, add a new small method that packs the
|
||
|
requested data into a buffer, etc. For the latter, you can perform a
|
||
|
modest amount of computation in this method; see the pack_xs()
|
||
|
function for an example.
|
||
|
|
||
|
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.
|
||
|
|
||
|
:line
|
||
|
|
||
|
Thermodynamic output options :link(thermo),h4
|
||
|
|
||
|
There is only one class that computes and prints thermodynamic
|
||
|
information to the screen and log file, although the
|
||
|
"thermo_style"_thermo_style.html command treats its options as styles.
|
||
|
|
||
|
There are several styles defined in thermo.cpp: "one", "multi", and
|
||
|
"granular". There is also a flexible "custom" style which allows you
|
||
|
to specify what quantities will be printed each timestep where
|
||
|
thermodynamics is computed. See the "thermo_style"_thermo_style.html
|
||
|
command for a list of pre-defined quantities.
|
||
|
|
||
|
Here is how you can extend the thermo output capabilities. Search the
|
||
|
thermo.cpp and thermo.h files for the word "customize" which will tell
|
||
|
you where to make these additions. Note that fixes can also print-out
|
||
|
thermodynamic quantities via the "fix_modify"_fix_modify.html command,
|
||
|
so you do not need to modify thermo.cpp to print fix information.
|
||
|
|
||
|
If you want to create a new style (like "one" or "granular") that
|
||
|
prints a collection of pre-defined quantities, you add a few lines
|
||
|
that define the new style to thermo.cpp. First, add a #DEFINE line at
|
||
|
the top of the file which lists the quantities to print. Then add the
|
||
|
style name you have chosen to the if test in the constructor to copy
|
||
|
the defined string to the line[] variable.
|
||
|
|
||
|
You can also add new quantities to the custom list. Add your new
|
||
|
keyword to the if test in the parse_fields() function where the call
|
||
|
to addfield() specifies the text string (8 character max) that will be
|
||
|
printed with the quantity, the function that will compute it, and the
|
||
|
data type (INT,FLOAT) of the quantity. Then at the bottom of the
|
||
|
file, add a function compute_*() which computes the quantity you wish
|
||
|
to print. The function assigns the quantity to the variable "dvalue"
|
||
|
if it is a floating-point quantity, or to "ivalue" if it is an
|
||
|
integer. See the other compute_*() functions for examples of how
|
||
|
various quantities can be accessed, computed, summed across
|
||
|
processors, normalized as per-atom values, etc. Also, if it makes
|
||
|
sense to allow the quantity to be stored in a variable in the input
|
||
|
script, add a couple of lines to the compute_value() function that is
|
||
|
called when a variable is evaluated. Finally, add a prototype for
|
||
|
your new compute method to thermo.h.
|
||
|
|
||
|
:line
|
||
|
|
||
|
Temperature computation options :link(temp),h4
|
||
|
|
||
|
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"_fix_nvt.html of "fix langevin"_fix_langevin.html commands.
|
||
|
|
||
|
Temp_full.cpp and temp_full.h are the simplest example of a
|
||
|
Temperature class. They implement the {full} style of the
|
||
|
"temperature"_temperature.html command.
|
||
|
|
||
|
Here is a brief description of the class methods in temperature.h:
|
||
|
|
||
|
init: setup the temperature computation
|
||
|
compute: compute and return temperature :tb(s=:)
|
||
|
|
||
|
:line
|
||
|
|
||
|
Region geometry options :link(region),h4
|
||
|
|
||
|
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"_region.html command.
|
||
|
|
||
|
Here is a brief description of the single class method required:
|
||
|
|
||
|
match: determine whether a point is in the region :tb(s=:)
|
||
|
|
||
|
:line
|
||
|
|
||
|
Fix options :link(fix),h4
|
||
|
|
||
|
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"_fix_enforce2d.html which
|
||
|
corresponds to the {enforce2d} style) or as complicated as applying
|
||
|
SHAKE constraints on bonds and angles (see "fix shake"_fix_shake.html
|
||
|
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
|
||
|
thermo_fields: define quantities for thermodynamic output
|
||
|
thermo_compute: compute thermodynamic quantities :tb(s=:)
|
||
|
|
||
|
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. For an end_of_step fix, one of your
|
||
|
fix arguments must be the variable "nevery" which is used to determine
|
||
|
when to call the fix. By convention, this is the first argument the
|
||
|
fix defines (after the ID, group-ID, style).
|
||
|
|
||
|
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"_run_style.html command), the initial_integrate,
|
||
|
post_force_integrate, and final_integrate_respa methods can be
|
||
|
implemented. The thermo_fields and thermo_compute methods enable a
|
||
|
fix to contribute values to thermodynamic output, as printed
|
||
|
quantities and/or to be summed to the potential energy of the system.
|
||
|
|
||
|
:line
|
||
|
|
||
|
Atom options :link(atom),h4
|
||
|
|
||
|
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"_atom_style.html 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
|
||
|
:tb(s=:)
|
||
|
|
||
|
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
|
||
|
:tb(s=:)
|
||
|
|
||
|
:line
|
||
|
|
||
|
Variable options :link(variable),h4
|
||
|
|
||
|
The variable class stores and evaluates input script variables $a, $b,
|
||
|
... $z, as described in "this section"_Section_commands.html#3_2.
|
||
|
{Equal}-style variables are defined by an equation that is evaulated
|
||
|
each time the variable is used. The equation can include functions,
|
||
|
vectors, keywords, and numbers as described in the
|
||
|
"variable"_variable.html command. The list of valid functions,
|
||
|
vectors, and keywords, can be extended by adding a few lines of code
|
||
|
to the evaluate() method at the end of the variable.cpp file. Search
|
||
|
for the word "customize" to find the correct locations for adding
|
||
|
code.
|
||
|
|
||
|
A new function (e.g. foo(arg1,arg2,...)) can be added in the section
|
||
|
that starts with the comment
|
||
|
|
||
|
// customize by adding function to this list and to if statement :pre
|
||
|
|
||
|
A new vector (e.g. q[]) can be added in the section that starts with
|
||
|
the comment
|
||
|
|
||
|
// customize by adding vector to this list and to if statement :pre
|
||
|
|
||
|
A new keyword (e.g. mysum) can be added in the section that starts with
|
||
|
the comment
|
||
|
|
||
|
// customize by adding keyword to this list and to if statement :pre
|
||
|
|
||
|
Note that keywords supported by the "thermo_style
|
||
|
custom"_themo_style.html command are evaluated by the thermo routines,
|
||
|
so do not need to be added to variable.cpp.
|
||
|
|
||
|
:line
|
||
|
|
||
|
New top-level commands :link(command),h4
|
||
|
|
||
|
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 :tb(s=:)
|
||
|
|
||
|
Of course, the new class can define other methods and variables that
|
||
|
it uses internally.
|
||
|
|
||
|
:line
|
||
|
|
||
|
:link(Foo)
|
||
|
[(Foo)] Foo, Morefoo, and Maxfoo, J of Classic Potentials, 75, 345 (1997).
|