Merge pull request #2312 from akohlmey/developer-guide

Integrate text from developer.tex file to the manual
This commit is contained in:
Axel Kohlmeyer 2020-08-28 15:01:27 -04:00 committed by GitHub
commit ded657120d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 647 additions and 927 deletions

View File

@ -54,7 +54,7 @@ DOXYFILES = $(shell sed -n -e 's/\#.*$$//' -e '/^ *INPUT \+=/,/^[A-Z_]\+ \+
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html create HTML doc pages in html dir"
@echo " pdf create Developer.pdf and Manual.pdf in this dir"
@echo " pdf create Manual.pdf in this dir"
@echo " fetch fetch HTML and PDF files from LAMMPS web site"
@echo " epub create ePUB format manual for e-book readers"
@echo " mobi convert ePUB to MOBI format manual for e-book readers (e.g. Kindle)"
@ -69,7 +69,7 @@ help:
# ------------------------------------------
clean-all: clean
rm -rf $(BUILDDIR)/docenv $(MATHJAX) $(BUILDDIR)/LAMMPS.mobi $(BUILDDIR)/LAMMPS.epub $(BUILDDIR)/Manual.pdf $(BUILDDIR)/Developer.pdf
rm -rf $(BUILDDIR)/docenv $(MATHJAX) $(BUILDDIR)/LAMMPS.mobi $(BUILDDIR)/LAMMPS.epub $(BUILDDIR)/Manual.pdf
clean: clean-spelling
rm -rf $(BUILDDIR)/html $(BUILDDIR)/epub $(BUILDDIR)/latex $(BUILDDIR)/doctrees $(BUILDDIR)/doxygen/xml $(BUILDDIR)/doxygen-warn.log $(BUILDDIR)/doxygen/Doxyfile $(SPHINXCONFIG)/conf.py
@ -139,13 +139,6 @@ mobi: epub
pdf: xmlgen $(VENV) $(SPHINXCONFIG)/conf.py $(ANCHORCHECK)
@$(MAKE) $(MFLAGS) -C graphviz all
@if [ "$(HAS_PDFLATEX)" == "NO" ] ; then echo "PDFLaTeX was not found! Please check README.md for further instructions" 1>&2; exit 1; fi
@(\
cd src/Developer; \
pdflatex developer; \
pdflatex developer; \
mv developer.pdf ../../Developer.pdf; \
cd ../../; \
)
@(\
. $(VENV)/bin/activate ; env PYTHONWARNINGS= \
sphinx-build $(SPHINXEXTRA) -b latex -c $(SPHINXCONFIG) -d $(BUILDDIR)/doctrees $(RSTDIR) latex ;\
@ -175,12 +168,11 @@ pdf: xmlgen $(VENV) $(SPHINXCONFIG)/conf.py $(ANCHORCHECK)
@rm -rf latex/USER
@cp -r src/PDF latex/PDF
@rm -rf latex/PDF/.[sg]*
@echo "Build finished. Manual.pdf and Developer.pdf are in this directory."
@echo "Build finished. Manual.pdf is in this directory."
fetch:
@rm -rf html_www Manual_www.pdf Developer_www.pdf
@rm -rf html_www Manual_www.pdf
@curl -s -o Manual_www.pdf http://lammps.sandia.gov/doc/Manual.pdf
@curl -s -o Developer_www.pdf http://lammps.sandia.gov/doc/Developer.pdf
@curl -s -o lammps-doc.tar.gz http://lammps.sandia.gov/tars/lammps-doc.tar.gz
@tar xzf lammps-doc.tar.gz
@rm -f lammps-doc.tar.gz

View File

@ -471,7 +471,7 @@ LAMMPS source distribution.
.. code-block:: bash
make html # create HTML doc pages in html directory
make pdf # create Developer.pdf and Manual.pdf in this directory
make pdf # create Manual.pdf in this directory
make fetch # fetch HTML and PDF files from LAMMPS web site
make clean # remove all intermediate files
make clean-all # reset the entire doc build environment

View File

@ -1,3 +0,0 @@
/developer.aux
/developer.log
/developer.toc

View File

@ -1,198 +0,0 @@
#FIG 3.2 Produced by xfig version 3.2.5a
Portrait
Center
Inches
Letter
100.00
Single
-2
1200 2
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2232 1170 3540 1170 3540 1505 2232 1505 2232 1170
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2220 1830 3015 1830 3015 2219 2220 2219 2220 1830
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2226 3285 3300 3285 3300 3665 2226 3665 2226 3285
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2223 5190 3225 5190 3225 5525 2223 5525 2223 5190
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2232 7125 3090 7125 3090 7478 2232 7478 2232 7125
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2226 10230 3300 10230 3300 10565 2226 10565 2226 10230
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4026 10305 4980 10305 4980 10592 4026 10592 4026 10305
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4029 9900 5205 9900 5205 10250 4029 10250 4029 9900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4038 9315 5370 9315 5370 9659 4038 9659 4038 9315
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4023 8955 4530 8955 4530 9278 4023 9278 4023 8955
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4029 8475 5190 8475 5190 8762 4029 8762 4029 8475
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4008 8115 5430 8115 5430 8408 4008 8408 4008 8115
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4026 7425 4995 7425 4995 7712 4026 7712 4026 7425
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4035 6720 4650 6720 4650 7025 4035 7025 4035 6720
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4044 7080 4830 7080 4830 7358 4044 7358 4044 7080
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4032 6105 5205 6105 5205 6419 4032 6419 4032 6105
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4026 5715 5115 5715 5115 6062 4026 6062 4026 5715
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4023 3585 4605 3585 4605 3872 4023 3872 4023 3585
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3954 1680 5175 1680 5175 1997 3954 1997 3954 1680
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
1620 5235 2100 615
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
1605 5445 2070 10695
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3120 1935 3855 1800
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3150 2115 3765 2250
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3135 7230 3945 6840
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3150 7335 3945 8610
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
5265 8610 6195 8400
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
5280 8655 6180 8820
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3345 10290 3930 10020
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3360 10395 3930 10425
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3360 10455 3930 10755
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2193 360 3435 360 3435 647 2193 647 2193 360
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3398 3472 3923 3307
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3413 3601 3923 3721
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3285 2806 3870 2802
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3315 5372 3900 5368
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6354 2280 7470 2280 7470 2585 6354 2585 6354 2280
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6348 1875 7320 1875 7320 2222 6348 2222 6348 1875
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3954 2070 5505 2070 5505 2372 3954 2372 3954 2070
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
5634 2137 6230 2045
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
5670 2310 6265 2418
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3900 2640 5400 2640 5400 2975 3900 2975 3900 2640
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4038 3165 5385 3165 5385 3497 4038 3497 4038 3165
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4245 4110 5730 4110 5730 4499 4245 4499 4245 4110
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4233 4545 6390 4545 6390 4862 4233 4862 4233 4545
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4026 5190 5385 5190 5385 5525 4026 5525 4026 5190
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4038 7755 5310 7755 5310 8075 4038 8075 4038 7755
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6270 8250 7365 8250 7365 8610 6270 8610 6270 8250
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6273 8655 7380 8655 7380 8978 6273 8978 6273 8655
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4041 10620 5985 10620 5985 10943 4041 10943 4041 10620
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2217 10830 3135 10830 3135 11156 2217 11156 2217 10830
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2229 9780 3240 9780 3240 10118 2229 10118 2229 9780
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2214 9015 3285 9015 3285 9362 2214 9362 2214 9015
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2208 5850 3420 5850 3420 6209 2208 6209 2208 5850
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2217 4275 3615 4275 3615 4634 2217 4634 2217 4275
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2235 2655 3150 2655 3150 3000 2235 3000 2235 2655
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
60 5115 1500 5115 1500 5610 60 5610 60 5115
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3486 6018 4011 5853
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3486 6129 3996 6249
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3361 9291 3991 9531
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3345 9129 4005 9099
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3691 4412 4216 4277
2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
1 1 2.00 120.00 240.00
3695 4561 4175 4711
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2220 735 3129 735 3129 1043 2220 1043 2220 735
4 0 1 50 -1 18 18 0.0000 4 225 1275 2265 1455 Universe\001
4 0 1 50 -1 18 18 0.0000 4 285 735 2265 2175 Input\001
4 0 1 50 -1 18 18 0.0000 4 225 780 2265 2925 Atom\001
4 0 1 50 -1 18 18 0.0000 4 285 1020 2265 3600 Update\001
4 0 1 50 -1 18 18 0.0000 4 285 1320 2265 4575 Neighbor\001
4 0 1 50 -1 18 18 0.0000 4 225 945 2265 5475 Comm\001
4 0 1 50 -1 18 18 0.0000 4 225 1110 2265 6150 Domain\001
4 0 1 50 -1 18 18 0.0000 4 225 810 2265 7425 Force\001
4 0 1 50 -1 18 18 0.0000 4 285 975 2265 9300 Modify\001
4 0 1 50 -1 18 18 0.0000 4 285 900 2265 10050 Group\001
4 0 1 50 -1 18 18 0.0000 4 285 990 2265 10500 Output\001
4 0 1 50 -1 18 18 0.0000 4 225 825 2265 11100 Timer\001
4 0 0 50 -1 18 18 0.0000 4 225 1170 3990 1950 Variable\001
4 0 4 50 -1 18 18 0.0000 4 225 1470 3990 2325 Command\001
4 0 4 50 -1 18 18 0.0000 4 285 1275 4065 3450 Integrate\001
4 0 4 50 -1 18 18 0.0000 4 225 525 4065 3825 Min\001
4 0 0 50 -1 18 18 0.0000 4 285 1230 4065 5475 Irregular\001
4 0 4 50 -1 18 18 0.0000 4 285 1020 4065 6000 Region\001
4 0 0 50 -1 18 18 0.0000 4 225 975 4065 6375 Lattice\001
4 0 4 50 -1 18 18 0.0000 4 225 435 4065 9225 Fix\001
4 0 4 50 -1 18 18 0.0000 4 285 1305 4065 9600 Compute\001
4 0 4 50 -1 18 18 0.0000 4 225 570 4065 6975 Pair\001
4 0 4 50 -1 18 18 0.0000 4 285 840 4065 7665 Angle\001
4 0 4 50 -1 18 18 0.0000 4 225 1215 4065 8010 Dihedral\001
4 0 4 50 -1 18 18 0.0000 4 285 1305 4065 8355 Improper\001
4 0 4 50 -1 18 18 0.0000 4 285 1095 4065 8700 KSpace\001
4 0 4 50 -1 18 18 0.0000 4 285 855 4065 10545 Dump\001
4 0 0 50 -1 18 18 0.0000 4 225 1815 4065 10890 WriteRestart\001
4 0 0 50 -1 18 18 0.0000 4 225 930 6315 8550 FFT3D\001
4 0 0 50 -1 18 18 0.0000 4 285 1005 6315 8925 Remap\001
4 0 0 50 -1 18 18 0.0000 4 225 885 6390 2175 Finish\001
4 0 0 50 -1 18 18 0.0000 4 285 1050 6390 2550 Special\001
4 0 4 50 -1 18 18 0.0000 4 225 1305 3990 2925 AtomVec\001
4 0 4 50 -1 18 18 0.0000 4 225 765 4065 7320 Bond\001
4 0 0 50 -1 18 18 0.0000 4 225 1095 4065 10200 Thermo\001
4 0 0 50 -1 18 18 0.0000 4 285 1380 4305 4425 NeighList\001
4 0 0 50 -1 18 18 0.0000 4 285 2025 4305 4800 NeighRequest\001
4 0 1 50 -1 18 18 0.0000 4 285 1155 2250 600 Memory\001
4 0 0 50 -1 18 18 0.0000 4 225 1305 120 5475 LAMMPS\001
4 0 1 50 -1 18 18 0.0000 4 225 735 2265 1005 Error\001

Binary file not shown.

View File

@ -1,699 +0,0 @@
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\centerline{\Large \bf LAMMPS Developer Guide}
\centerline{\bf 23 Aug 2011}
\vspace{0.5in}
This document is a developer guide to the LAMMPS molecular dynamics
package, whose WWW site is at lammps.sandia.gov. It describes the
internal structure and algorithms of the code. Sections will be added
as we have time, and in response to requests from developers and
users.
\tableofcontents
\pagebreak
\section{LAMMPS source files}
LAMMPS source files are in two directories of the distribution
tarball. The src directory has the majority of them, all of which are
C++ files (*.cpp and *.h). Many of these files are in the src
directory itself. There are also dozens of ``packages'', which can be
included or excluded when LAMMPS is built. See the
doc/Section\_build.html section of the manual for more information
about packages, or type ``make'' from within the src directory, which
lists package-related commands, such as ``make package-status''. The
source files for each package are in an all-uppercase sub-directory of
src, like src/MOLECULE or src/USER-CUDA. If the package is currently
installed, copies of the package source files will also exist in the
src directory itself. The src/STUBS sub-directory is not a package
but contains a dummy version of the MPI library, used when building a
serial version of the code.
The lib directory also contains source code for external libraries,
used by a few of the packages. Each sub-directory, like meam or gpu,
contains the source files, some of which are in different languages
such as Fortran. The files are compiled into libraries from within
each sub-directory, e.g. performing a ``make'' in the lib/meam directory
creates a libmeam.a file. These libraries are linked to during a
LAMMPS build, if the corresponding package is installed.
LAMMPS C++ source files almost always come in pairs, such as run.cpp
and run.h. The pair of files defines a C++ class, the Run class in
this case, which contains the code invoked by the ``run'' command in a
LAMMPS input script. As this example illustrates, source file and
class names often have a one-to-one correspondence with a command used
in a LAMMPS input script. Some source files and classes do not have a
corresponding input script command, e.g. ``force.cpp'' and the Force
class. They are discussed in the next section.
\pagebreak
\section{Class hierarchy of LAMMPS}
Though LAMMPS has a lot of source files and classes, its class
hierarchy is quite simple, as outlined in Fig \ref{fig:classes}. Each
boxed name refers to a class and has a pair of associated source files
in lammps/src, e.g. ``memory.cpp'' and ``memory.h''. More details on the
class and its methods and data structures can be found by examining
its *.h file.
LAMMPS (lammps.cpp/h) is the top-level class for the entire code. It
holds an ``instance'' of LAMMPS and can be instantiated one or more
times by a calling code. For example, the file src/main.cpp simply
instantiates one instance of LAMMPS and passes it the input script.
The file src/library.cpp contains a C-style library interface to the
LAMMPS class. See the lammps/couple and lammps/python directories for
examples of simple programs that use LAMMPS through its library
interface. A driver program can instantiate the LAMMPS class multiple
times, e.g. to embed several atomistic simulation regions within a
mesoscale or continuum simulation domain.
There are a dozen or so top-level classes within the LAMMPS class that
are visible everywhere in the code. They are shaded blue in Fig
\ref{fig:classes}. Thus any class can refer to the y-coordinate of
local atom $I$ as atom$\rightarrow$x[i][1]. This visibility is
enabled by a bit of cleverness in the Pointers class (see
src/pointers.h) which every class inherits from.
There are a handful of virtual parent classes in LAMMPS that define
what LAMMPS calls ``styles''. They are shaded red in Fig
\ref{fig:classes}. Each of these are parents of a number of child
classes that implement the interface defined by the parent class. For
example, the fix style has around 100 child classes. They are the
possible fixes that can be specified by the fix command in an input
script, e.g. fix nve, fix shake, fix ave/time, etc. The corresponding
classes are Fix (for the parent class), FixNVE, FixShake, FixAveTime,
etc. The source files for these classes are easy to identify in the
src directory, since they begin with the word ``fix'', e,g,
fix\_nve.cpp, fix\_shake,cpp, fix\_ave\_time.cpp, etc.
The one exception is child class files for the ``command'' style. These
implement specific commands in the input script that can be invoked
before/after/between runs or which launch a simulation. Examples are
the create\_box, minimize, run, and velocity commands which encode the
CreateBox, Minimize, Run, and Velocity classes. The corresponding
files are create\_box,cpp, minimize.cpp, run.cpp, and velocity.cpp.
The list of command style files can be found by typing ``grep
COMMAND\_CLASS *.h'' from within the src directory, since that word in
the header file identifies the class as an input script command.
Similar words can be grepped to list files for the other LAMMPS
styles. E.g. ATOM\_CLASS, PAIR\_CLASS, BOND\_CLASS, REGION\_CLASS,
FIX\_CLASS, COMPUTE\_CLASS, DUMP\_CLASS, etc.
\begin{figure}[htb]
\begin{center}
\includegraphics[height=4in]{classes.pdf}
\end{center}
\caption{Class hierarchy within LAMMPS source code.}
\label{fig:classes}
\end{figure}
More details on individual classes in Fig \ref{fig:classes} are as
follows:
\begin{itemize}
\item The Memory class handles allocation of all large vectors and
arrays.
\item The Error class prints all error and warning messages.
\item The Universe class sets up partitions of processors so that
multiple simulations can be run, each on a subset of the processors
allocated for a run, e.g. by the mpirun command.
\item The Input class reads an input script, stores variables, and
invokes stand-alone commands that are child classes of the Command
class.
\item As discussed above, the Command class is a parent class for
certain input script commands that perform a one-time operation
before/after/between simulations or which invoke a simulation. They
are instantiated from within the Input class, invoked, then
immediately destructed.
\item The Finish class is instantiated to print statistics to the
screen after a simulation is performed, by commands like run and
minimize.
\item The Special class walks the bond topology of a molecular system
to find first, second, third neighbors of each atom. It is invoked by
several commands, like read\_data, read\_restart, and replicate.
\item The Atom class stores all per-atom arrays. More precisely, they
are allocated and stored by the AtomVec class, and the Atom class
simply stores a pointer to them. The AtomVec class is a parent
class for atom styles, defined by the atom\_style command.
\item The Update class holds an integrator and a minimizer. The
Integrate class is a parent style for the Verlet and rRESPA time
integrators, as defined by the run\_style input command. The Min
class is a parent style for various energy minimizers.
\item The Neighbor class builds and stores neighbor lists. The
NeighList class stores a single list (for all atoms). The
NeighRequest class is called by pair, fix, or compute styles when
they need a particular kind of neighbor list.
\item The Comm class performs interprocessor communication, typically
of ghost atom information. This usually involves MPI message
exchanges with 6 neighboring processors in the 3d logical grid of
processors mapped to the simulation box. Sometimes the Irregular
class is used, when atoms may migrate to arbitrary processors.
\item The Domain class stores the simulation box geometry, as well as
geometric Regions and any user definition of a Lattice. The latter
are defined by region and lattice commands in an input script.
\item The Force class computes various forces between atoms. The Pair
parent class is for non-bonded or pair-wise forces, which in LAMMPS
lingo includes many-body forces such as the Tersoff 3-body
potential. The Bond, Angle, Dihedral, Improper parent classes are
styles for bonded interactions within a static molecular topology.
The KSpace parent class is for computing long-range Coulombic
interactions. One of its child classes, PPPM, uses the FFT3D and
Remap classes to communicate grid-based information with neighboring
processors.
\item The Modify class stores lists of Fix and Compute classes, both
of which are parent styles.
\item The Group class manipulates groups that atoms are assigned to
via the group command. It also computes various attributes of
groups of atoms.
\item The Output class is used to generate 3 kinds of output from a
LAMMPS simulation: thermodynamic information printed to the screen
and log file, dump file snapshots, and restart files. These
correspond to the Thermo, Dump, and WriteRestart classes
respectively. The Dump class is a parent style.
\item The Timer class logs MPI timing information, output at the end
of a run.
\end{itemize}
%%\pagebreak
%%\section{Spatial decomposition and parallel operations}
%%distributed memory
%%Ref to JCP paper
%%diagram of 3d grid of procs and spatial decomp
%%6-way comm
%%ghost atoms, PBC added when comm (in atom class)
%%\pagebreak
%%\section{Fixes, computes, variables}
%%fixes intercolate in timestep, store per-atom info
%%computes based on current snapshot
%%equal- and atom-style variables
%%output they produce - see write-up in HowTo
\pagebreak
\section{How a timestep works}
The first and most fundamental operation within LAMMPS to understand
is how a timestep is structured. Timestepping is performed by the
Integrate class within the Update class. Since Integrate is a parent
class, corresponding to the run\_style input script command, it has
child classes. In this section, the timestep implemented by the
Verlet child class is described. A similar timestep is implemented by
the Respa child class, for the rRESPA hierarchical timestepping
method. The Min parent class performs energy minimization, so does
not perform a literal timestep. But it has logic similar to what is
described here, to compute forces and invoke fixes at each iteration
of a minimization. Differences between time integration and
minimization are highlighted at the end of this section.
The Verlet class is encoded in the src/verlet.cpp and verlet.h files.
It implements the velocity-Verlet timestepping algorithm. The
workhorse method is Verlet::run(), but first we highlight several
other methods in the class.
\begin{itemize}
\item The init() method is called at the beginning of each dynamics
run. It simply sets some internal flags, based on user settings in
other parts of the code.
\item The setup() or setup\_minimal() methods are also called before
each run. The velocity-Verlet method requires current forces be
calculated before the first timestep, so these routines compute
forces due to all atomic interactions, using the same logic that
appears in the timestepping described next. A few fixes are also
invoked, using the mechanism described in the next section. Various
counters are also initialized before the run begins. The
setup\_minimal() method is a variant that has a flag for performing
less setup. This is used when runs are continued and information
from the previous run is still valid. For example, if repeated
short LAMMPS runs are being invoked, interleaved by other commands,
via the ``pre no'' and ``every'' options of the run command, the
setup\_minimal() method is used.
\item The force\_clear() method initializes force and other arrays to
zero before each timestep, so that forces (torques, etc) can be
accumulated.
\end{itemize}
Now for the Verlet::run() method. Its structure in hi-level pseudo
code is shown in Fig \ref{fig:verlet}. In the actual code in
src/verlet.cpp some of these operations are conditionally invoked.
\begin{figure}[htb]
\begin{center}
\begin{verbatim}
loop over N timesteps:
ev_set()
fix->initial_integrate()
fix->post_integrate()
nflag = neighbor->decide()
if nflag:
fix->pre_exchange()
domain->pbc()
domain->reset_box()
comm->setup()
neighbor->setup_bins()
comm->exchange()
comm->borders()
fix->pre_neighbor()
neighbor->build()
else
comm->forward_comm()
force_clear()
fix->pre_force()
pair->compute()
bond->compute()
angle->compute()
dihedral->compute()
improper->compute()
kspace->compute()
comm->reverse_comm()
fix->post_force()
fix->final_integrate()
fix->end_of_step()
if any output on this step: output->write()
\end{verbatim}
\end{center}
\caption{Pseudo-code for the Verlet::run() method.}
\label{fig:verlet}
\end{figure}
The ev\_set() method (in the parent Integrate class), sets two flags
({\em eflag} and {\em vflag}) for energy and virial computation. Each
flag encodes whether global and/or per-atom energy and virial should
be calculated on this timestep, because some fix or variable or output
will need it. These flags are passed to the various methods that
compute particle interactions, so that they can skip the extra
calculations if the energy and virial are not needed. See the
comments with the Integrate::ev\_set() method which document the flag
values.
At various points of the timestep, fixes are invoked,
e.g. fix$\rightarrow$initial\_integrate(). In the code, this is
actually done via the Modify class which stores all the Fix objects
and lists of which should be invoked at what point in the timestep.
Fixes are the LAMMPS mechanism for tailoring the operations of a
timestep for a particular simulation. As described elsewhere
(unwritten section), each fix has one or more methods, each of which
is invoked at a specific stage of the timestep, as in Fig
\ref{fig:verlet}. All the fixes defined in an input script with an
initial\_integrate() method are invoked at the beginning of each
timestep. Fix nve, nvt, npt are examples, since they perform the
start-of-timestep velocity-Verlet integration to update velocities by
a half-step, and coordinates by a full step. The post\_integrate()
method is next. Only a few fixes use this, e.g. to reflect particles
off box boundaries in the FixWallReflect class.
The decide() method in the Neighbor class determines whether neighbor
lists need to be rebuilt on the current timestep. If not, coordinates
of ghost atoms are acquired by each processor via the forward\_comm()
method of the Comm class. If neighbor lists need to be built, several
operations within the inner if clause of Fig \ref{fig:verlet} are
first invoked. The pre\_exchange() method of any defined fixes is
invoked first. Typically this inserts or deletes particles from the
system.
Periodic boundary conditions are then applied by the Domain class via
its pbc() method to remap particles that have moved outside the
simulation box back into the box. Note that this is not done every
timestep. but only when neighbor lists are rebuilt. This is so that
each processor's sub-domain will have consistent (nearby) atom
coordinates for its owned and ghost atoms. It is also why dumped atom
coordinates can be slightly outside the simulation box.
The box boundaries are then reset (if needed) via the reset\_box()
method of the Domain class, e.g. if box boundaries are shrink-wrapped
to current particle coordinates. A change in the box size or shape
requires internal information for communicating ghost atoms (Comm
class) and neighbor list bins (Neighbor class) be updated. The
setup() method of the Comm class and setup\_bins() method of the
Neighbor class perform the update.
The code is now ready to migrate atoms that have left a processor's
geometric sub-domain to new processors. The exchange() method of the
Comm class performs this operation. The borders() method of the Comm
class then identifies ghost atoms surrounding each processor's
sub-domain and communicates ghost atom information to neighboring
processors. It does this by looping over all the atoms owned by a
processor to make lists of those to send to each neighbor processor.
On subsequent timesteps, the lists are used by the
Comm::forward\_comm() method.
Fixes with a pre\_neighbor() method are then called. These typically
re-build some data structure stored by the fix that depends on the
current atoms owned by each processor.
Now that each processor has a current list of its owned and ghost
atoms, LAMMPS is ready to rebuild neighbor lists via the build()
method of the Neighbor class. This is typically done by binning all
owned and ghost atoms, and scanning a stencil of bins around each
owned atom's bin to make a Verlet list of neighboring atoms within the
force cutoff plus neighbor skin distance.
In the next portion of the timestep, all interaction forces between
particles are computed, after zeroing the per-atom force vector via
the force\_clear() method. If the newton flag is set to ``on'' by the
newton command, forces on both owned and ghost atoms are calculated.
Pairwise forces are calculated first, which enables the global virial
(if requested) to be calculated cheaply (at the end of the
Pair::compute() method), by a dot product of atom coordinates and
forces. By including owned and ghost atoms in the dot product, the
effect of periodic boundary conditions is correctly accounted for.
Molecular topology interactions (bonds, angles, dihedrals, impropers)
are calculated next. The final contribution is from long-range
Coulombic interactions, invoked by the KSpace class.
If the newton flag is on, forces on ghost atoms are communicated and
summed back to their corresponding owned atoms. The reverse\_comm()
method of the Comm class performs this operation, which is essentially
the inverse operation of sending copies of owned atom coordinates to
other processor's ghost atoms.
At this point in the timestep, the total force on each atom is known.
Additional force constraints (external forces, SHAKE, etc) are applied
by Fixes that have a post\_force() method. The second half of the
velocity-Verlet integration is then performed (another half-step
update of the velocities) via fixes like nve, nvt, npt.
At the end of the timestep, fixes that define an end\_of\_step()
method are invoked. These typically perform a diagnostic calculation,
e.g. the ave/time and ave/spatial fixes. The final operation of the
timestep is to perform any requested output, via the write() method of
the Output class. There are 3 kinds of LAMMPS output: thermodynamic
output to the screen and log file, snapshots of atom data to a dump
file, and restart files. See the thermo\_style, dump, and restart
commands for more details.
The iteration performed by an energy minimization is similar to the
dynamics timestep of Fig \ref{fig:verlet}. Forces are computed,
neighbor lists are built as needed, atoms migrate to new processors,
and atom coordinates and forces are communicated to neighboring
processors. The only difference is what Fix class operations are
invoked when. Only a subset of LAMMPS fixes are useful during energy
minimization, as explained in their individual doc pages. The
relevant Fix class methods are min\_pre\_exchange(),
min\_pre\_force(), and min\_post\_force(). Each is invoked at the
appropriate place within the minimization iteration. For example, the
min\_post\_force() method is analogous to the post\_force() method for
dynamics; it is used to alter or constrain forces on each atom, which
affects the minimization procedure.
\pagebreak
\section{Extending LAMMPS}
The Section\_modify.html file in the doc directory of
the LAMMPS distribution gives an overview of how LAMMPS can
be extended by writing new classes that derive from existing
parent classes in LAMMPS. Here, some specific coding
details are provided for writing a new fix.
\subsection{New fixes}
(this section provided by Kirill Lykov)
\vspace{0.25cm}
Writing fixes is a flexible way of extending LAMMPS. Users can
implement many things using fixes:
\begin{itemize}
\item changing particles attributes (positions, velocities, forces, etc.).
Example: FixFreeze.
\item reading/writing data. Example: FixRestart.
\item implementing boundary conditions. Example: FixWall.
\item saving information about particles for future use (previous positions,
for instance). Example: FixStoreState.
\end{itemize}
All fixes are derived from class Fix and must have constructor with the
signature: FixMine(class LAMMPS *, int, char **).
Every fix must be registered in LAMMPS by writing the following lines
of code in the header before include guards:
\begin{center}
\begin{verbatim}
#ifdef FIX_CLASS
FixStyle(your/fix/name,FixMine)
#else
\end{verbatim}
\end{center}
Where ``your/fix/name'' is a name of your fix in the script and FixMine
is the name of the class. This code allows LAMMPS to find your fix
when it parses input script. In addition, your fix header must be
included in the file ``style\_fix.h''. In case if you use LAMMPS make,
this file is generated automatically - all files starting with prefix
fix\_ are included, so call your header the same way. Otherwise, don't
forget to add your include into ``style\_fix.h''.
Let's write a simple fix which will print average velocity at the end
of each timestep. First of all, implement a constructor:
\begin{center}
\begin{verbatim}
FixPrintVel::FixPrintVel(LAMMPS *lmp, int narg, char **arg)
: Fix(lmp, narg, arg)
{
if (narg < 4)
error->all(FLERR,"Illegal fix print command");
nevery = atoi(arg[3]);
if (nevery <= 0)
error->all(FLERR,"Illegal fix print command");
}
\end{verbatim}
\end{center}
In the constructor you should parse your fix arguments which are
specified in the script. All fixes have pretty the same syntax: fix
[fix\_identifier] [group\_name] [fix\_name] [fix\_arguments]. The
first 3 parameters are parsed by Fix class constructor, while
[fix\_arguments] should be parsed by you. In our case, we need to
specify how often we want to print an average velocity. For instance,
once in 50 timesteps: fix 1 print/vel 50. There is a special variable
in Fix class called nevery which specifies how often method
end\_of\_step() is called. Thus all we need to do is just set it up.
The next method we need to implement is setmask():
\begin{center}
\begin{verbatim}
int FixPrintVel::setmask()
{
int mask = 0;
mask |= FixConst::END_OF_STEP;
return mask;
}
\end{verbatim}
\end{center}
Here user specifies which methods of your fix should be called during
the execution. For instance, END\_OF\_STEP corresponds to the
end\_of\_step() method. Overall, there are 8 most important methods,
methods are called in predefined order during the execution of the
verlet algorithm as was mentioned in the Section 3:
\begin{itemize}
\item initial\_integrate()
\item post\_integrate()
\item pre\_exchange()
\item pre\_neighbor()
\item pre\_force()
\item post\_force()
\item final\_integrate()
\item end\_of\_step()
\end{itemize}
Fix developer must understand when he wants to execute his code. In
case if we want to write FixPrintVel, we need only end\_of\_step():
\begin{center}
\begin{verbatim}
void FixPrintVel::end_of_step()
{
// for add3, scale3
using namespace MathExtra;
double** v = atom->v;
int nlocal = atom->nlocal;
double localAvgVel[4]; // 4th element for particles count
memset(localAvgVel, 0, 4 * sizeof(double));
for (int particleInd = 0; particleInd < nlocal; ++particleInd) {
add3(localAvgVel, v[particleInd], localAvgVel);
}
localAvgVel[3] = nlocal;
double globalAvgVel[4];
memset(globalAvgVel, 0, 4 * sizeof(double));
MPI_Allreduce(localAvgVel, globalAvgVel, 4, MPI_DOUBLE, MPI_SUM, world);
scale3(1.0 / globalAvgVel[3], globalAvgVel);
if (comm->me == 0) {
printf("\%e, \%e, \%e\n",
globalAvgVel[0], globalAvgVel[1], globalAvgVel[2]);
}
}
\end{verbatim}
\end{center}
In the code above, we use MathExtra routines defined in
``math\_extra.h''. There are bunch of math functions to work with
arrays of doubles as with math vectors.
In this code we use an instance of Atom class. This object is stored
in the Pointers class (see ``pointers.h''). This object contains all
global information about the simulation system. Data from Pointers
class available to all classes inherited from it using protected
inheritance. Hence when you write you own class, which is going to use
LAMMPS data, don't forget to inherit from Pointers. When writing
fixes we inherit from class Fix which is inherited from Pointers so
there is no need to inherit from it directly.
The code above computes average velocity for all particles in the
simulation. Yet you have one unused parameter in fix call from the
script - [group\_name]. This parameter specifies the group of atoms
used in the fix. So we should compute average for all particles in the
simulation if group\_name == all, but it can be any group. The group
information is specified by groupbit which is defined in class Fix:
\begin{center}
\begin{verbatim}
for (int particleInd = 0; particleInd < nlocal; ++particleInd) {
if (atom->mask[particleInd] & groupbit) {
//Do all job here
}
}
\end{verbatim}
\end{center}
Class Atom encapsulates atoms positions, velocities, forces, etc. User
can access them using particle index. Note, that particle indexes are
usually changed every timestep because of sorting.
Lets consider another Fix example. We want to have a fix which stores
atoms position from previous time step in your fix. The local atoms
indexes will not be valid on the next iteration. In order to handle
this situation there are several methods which should be implemented:
\begin{itemize}
\item \verb|double memory_usage| - return how much memory fix uses
\item \verb|void grow_arrays(int)| - do reallocation of the per particle arrays
in your fix
\item \verb|void copy_arrays(int i, int j, int delflag)| - copy i-th per-particle
information to j-th. Used when atoms sorting is performed. if delflag is set
and atom j owns a body, move the body information to atom i.
\item \verb|void set_arrays(int i)| - sets i-th particle related information to zero
\end{itemize}
Note, that if your class implements these methods, it must call add calls of
add\_callback and delete\_callback to constructor and destructor:
\begin{center}
\begin{verbatim}
FixSavePos::FixSavePos(LAMMPS *lmp, int narg, char **arg) {
//...
atom->add_callback(0);
}
FixSavePos::~FixSavePos() {
atom->delete_callback(id, 0);
}
\end{verbatim}
\end{center}
Since we want to store positions of atoms from previous timestep, we
need to add double** x to the header file. Than add allocation code to
constructor:
\verb|memory->create(this->x, atom->nmax, 3, "FixSavePos:x");|. Free memory
at destructor: \verb|memory->destroy(x);|
Finally, implement mentioned methods:
\begin{center}
\begin{verbatim}
double FixSavePos::memory_usage()
{
int nmax = atom->nmax;
double bytes = 0.0;
bytes += nmax * 3 * sizeof(double);
return bytes;
}
void FixSavePos::grow_arrays(int nmax)
{
memory->grow(this->x, nmax, 3, "FixSavePos:x");
}
void FixSavePos::copy_arrays(int i, int j, int delflag)
{
memcpy(this->x[j], this->x[i], sizeof(double) * 3);
}
void FixSavePos::set_arrays(int i)
{
memset(this->x[i], 0, sizeof(double) * 3);
}
int FixSavePos::pack_exchange(int i, double *buf)
{
int m = 0;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
return m;
}
int FixSavePos::unpack_exchange(int nlocal, double *buf)
{
int m = 0;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
return m;
}
\end{verbatim}
\end{center}
Now, a little bit about memory allocation. We used Memory class which
is just a bunch of template functions for allocating 1D and 2D
arrays. So you need to add include ``memory.h'' to have access to them.
Finally, if you need to write/read some global information used in
your fix to the restart file, you might do it by setting flag
restart\_global = 1 in the constructor and implementing methods void
write\_restart(FILE *fp) and void restart(char *buf).
\end{document}

View File

@ -23,7 +23,6 @@ this Intr are included in this list.
* `Mail list <https://lammps.sandia.gov/mail.html>`_
* `Workshops <https://lammps.sandia.gov/workshops.html>`_
* `Tutorials <https://lammps.sandia.gov/tutorials.html>`_
* `Developer guide <https://lammps.sandia.gov/Developer.pdf>`_
* `Pre- and post-processing tools for LAMMPS <https://lammps.sandia.gov/prepost.html>`_
* `Other software usable with LAMMPS <https://lammps.sandia.gov/offsite.html>`_

View File

@ -27,8 +27,7 @@ all LAMMPS development is coordinated.
The content for this manual is part of the LAMMPS distribution. You
can build a local copy of the Manual as HTML pages or a PDF file, by
following the steps on the :doc:`Manual build <Manual_build>` doc page.
There is also a `Developer.pdf <Developer.pdf>`_ document which gives
a brief description of the basic code structure of LAMMPS.
The manual is split into two parts: 1) User documentation and 2) Programmer documentation.
----------

View File

@ -14,7 +14,6 @@ files. Here is a list with descriptions:
lammps.1 # man page for the lammps command
msi2lmp.1 # man page for the msi2lmp command
Manual.pdf # large PDF version of entire manual
Developer.pdf # small PDF with info about how LAMMPS is structured
LAMMPS.epub # Manual in ePUB e-book format
LAMMPS.mobi # Manual in MOBI e-book format
docenv # virtualenv folder for processing the manual sources
@ -35,7 +34,7 @@ of two ways:
a. You can "fetch" the current HTML and PDF files from the LAMMPS web
site. Just type ``make fetch``. This should download a html_www
directory and Manual_www.pdf/Developer_www.pdf files. Note that if
directory and a Manual_www.pdf file. Note that if
new LAMMPS features have been added more recently than the date of
your LAMMPS version, the fetched documentation will include those
changes (but your source code will not, unless you update your local
@ -49,6 +48,11 @@ b. You can build the HTML or PDF files yourself, by typing ``make html``
only once, unless you type ``make clean-all``. After that, viewing and
processing of the documentation can be done without internet access.
A current version of the manual (latest patch release, aka unstable branch)
is is available online at: `https://lammps.sandia.gov/doc/Manual.html <https://lammps.sandia.gov/doc/Manual.html>`_
A version of the manual corresponding to the ongoing development
(aka master branch) is available online at: `https://doc.lammps.org/ <https://doc.lammps.org/>`_
----------
The generation of all documentation is managed by the Makefile in the
@ -58,10 +62,9 @@ available:
.. code-block:: bash
make html # generate HTML in html dir using Sphinx
make pdf # generate 2 PDF files (Manual.pdf,Developer.pdf)
# in doc dir via htmldoc and pdflatex
make fetch # fetch HTML doc pages and 2 PDF files from web site
# as a tarball and unpack into html dir and 2 PDFs
make pdf # generate PDF as Manual.pdf using Sphinx and pdflatex
make fetch # fetch HTML doc pages and PDF file from web site
# as a tarball and unpack into html dir and PDF
make epub # generate LAMMPS.epub in ePUB format using Sphinx
make mobi # generate LAMMPS.mobi in MOBI format using ebook-convert

View File

@ -113,8 +113,630 @@ care has to be taken, that suitable communicators are used to not
create conflicts between different instances.
The LAMMPS class currently holds instances of 19 classes representing
different core functionalities
There are a handful of virtual parent classes in LAMMPS that define
what LAMMPS calls ``styles``. They are shaded red in Fig
\ref{fig:classes}. Each of these are parents of a number of child
classes that implement the interface defined by the parent class.
different core functionalities There are a handful of virtual parent
classes in LAMMPS that define what LAMMPS calls ``styles``. They are
shaded red in the :ref:`class-topology` figure. Each of these are
parents of a number of child classes that implement the interface
defined by the parent class. There are two main categories of these
``styles``: some may only have one instance active at a time (e.g. atom,
pair, bond, angle, dihedral, improper, kspace, comm) and there is a
dedicated pointer variable in the composite class that manages them.
Setups that require a mix of different such styles have to use a
*hybrid* class that manages and forwards calls to the corresponding
sub-styles for the designated subset of atoms or data. or the composite
class may have lists of class instances, e.g. Modify handles lists of
compute and fix styles, while Output handles dumps class instances.
The exception to this scheme are the ``command`` style classes. These
implement specific commands that can be invoked before, after, or between
runs or are commands which launch a simulation. For these an instance
of the class is created, its command() method called and then, after
completion, the class instance deleted. Examples for this are the
create_box, create_atoms, minimize, run, or velocity command styles.
For all those ``styles`` certain naming conventions are employed: for
the fix nve command the class is called FixNVE and the files are
``fix_nve.h`` and ``fix_nve.cpp``. Similarly for fix ave/time we have
FixAveTime and ``fix_ave_time.h`` and ``fix_ave_time.cpp``. Style names
are lower case and without spaces or special characters. A suffix or
multiple appended with a forward slash '/' denotes a variant of the
corresponding class without the suffix. To connect the style name and
the class name, LAMMPS uses macros like the following ATOM\_CLASS,
PAIR\_CLASS, BOND\_CLASS, REGION\_CLASS, FIX\_CLASS, COMPUTE\_CLASS,
or DUMP\_CLASS in the corresponding header file. During compilation
files with the pattern ``style_name.h`` are created that contain include
statements including all headers of all styles of a given type that
are currently active (or "installed).
More details on individual classes in the :ref:`class-topology` are as
follows:
- The Memory class handles allocation of all large vectors and arrays.
- The Error class prints all error and warning messages.
- The Universe class sets up partitions of processors so that multiple
simulations can be run, each on a subset of the processors allocated
for a run, e.g. by the mpirun command.
- The Input class reads and processes input input strings and files,
stores variables, and invokes :doc:`commands <Commands_all>`.
- As discussed above, command style classes are directly derived from
the Pointers class. They provide input script commands that perform
one-time operations before/after/between simulations or which invoke a
simulation. They are instantiated from within the Input class,
invoked, then immediately destructed.
- The Finish class is instantiated to print statistics to the screen
after a simulation is performed, by commands like run and minimize.
- The Special class walks the bond topology of a molecular system to
find first, second, third neighbors of each atom. It is invoked by
several commands, like :doc:`read_data <read_data>`,
:doc:`read_restart <read_restart>`, or :doc:`replicate <replicate>`.
- The Atom class stores per-atom properties associated with atom styles.
More precisely, they are allocated and managed by a class derived from
the AtomVec class, and the Atom class simply stores pointers to them.
The classes derived from AtomVec represent the different atom styles
and they are instantiated through the :doc:`atom_style <atom_style>`
command.
- The Update class holds instances of an integrator and a minimizer
class. The Integrate class is a parent style for the Verlet and
r-RESPA time integrators, as defined by the :doc:`run_style
<run_style>` command. The Min class is a parent style for various
energy minimizers.
- The Neighbor class builds and stores neighbor lists. The NeighList
class stores a single list (for all atoms). A NeighRequest class
instance is created by pair, fix, or compute styles when they need a
particular kind of neighbor list and use the NeighRequest properties
to select the neighbor list settings for the given request. There can
be multiple instances of the NeighRequest class and the Neighbor class
will try to optimize how they are computed by creating copies or
sub-lists where possible.
- The Comm class performs inter-processor communication, typically of
ghost atom information. This usually involves MPI message exchanges
with 6 neighboring processors in the 3d logical grid of processors
mapped to the simulation box. There are two :doc:`communication styles
<comm_style>` enabling different ways to do the domain decomposition.
Sometimes the Irregular class is used, when atoms may migrate to
arbitrary processors.
- The Domain class stores the simulation box geometry, as well as
geometric Regions and any user definition of a Lattice. The latter
are defined by the :doc:`region <region>` and :doc:`lattice <lattice>`
commands in an input script.
- The Force class computes various forces between atoms. The Pair
parent class is for non-bonded or pair-wise forces, which in LAMMPS
also includes many-body forces such as the Tersoff 3-body potential if
those are computed by walking pairwise neighbor lists. The Bond,
Angle, Dihedral, Improper parent classes are styles for bonded
interactions within a static molecular topology. The KSpace parent
class is for computing long-range Coulombic interactions. One of its
child classes, PPPM, uses the FFT3D and Remap classes to redistribute
and communicate grid-based information across the parallel processors.
- The Modify class stores lists of class instances derived from the
:doc:`Fix <fix>` and :doc:`Compute <compute>` base classes.
- The Group class manipulates groups that atoms are assigned to via the
:doc:`group <group>` command. It also has functions to compute
various attributes of groups of atoms.
- The Output class is used to generate 3 kinds of output from a LAMMPS
simulation: thermodynamic information printed to the screen and log
file, dump file snapshots, and restart files. These correspond to the
:doc:`Thermo <thermo_style>`, :doc:`Dump <dump>`, and
:doc:`WriteRestart <write_restart>` classes respectively. The Dump
class is a base class with several derived classes implementing
various dump style variants.
- The Timer class logs timing information, output at the end
of a run.
.. TODO section on "Spatial decomposition and parallel operations"
.. diagram of 3d processor grid, brick vs. tiled. local vs. ghost
.. atoms, 6-way communication with pack/unpack functions,
.. PBC as part of the communication
.. TODO section on "Fixes, Computes, and Variables"
.. how and when data is computed and provided and how it is
.. referenced. flags in Fix/Compute/Variable classes tell
.. style and amount of available data.
How a timestep works
====================
The first and most fundamental operation within LAMMPS to understand is
how a timestep is structured. Timestepping is performed by calling
methods of the Integrate class instance within the Update class. Since
Integrate is a base class, it will point to an instance of a derived
class corresponding to what is selected by the :doc:`run_style
<run_style>` input script command.
In this section, the timestep implemented by the Verlet class is
described. A similar timestep protocol is implemented by the Respa
class, for the r-RESPA hierarchical timestepping method.
The Min base class performs energy minimization, so does not perform a
literal timestep. But it has logic similar to what is described here,
to compute forces and invoke fixes at each iteration of a minimization.
Differences between time integration and minimization are highlighted at
the end of this section.
The Verlet class is encoded in the ``src/verlet.cpp`` and ``verlet.h``
files. It implements the velocity-Verlet timestepping algorithm. The
workhorse method is ``Verlet::run()``, but first we highlight several
other methods in the class.
- The ``init()`` method is called at the beginning of each dynamics
run. It simply sets some internal flags, based on user settings in
other parts of the code.
- The ``setup()`` or ``setup_minimal()`` methods are also called before
each run. The velocity-Verlet method requires current forces be
calculated before the first timestep, so these routines compute
forces due to all atomic interactions, using the same logic that
appears in the timestepping described next. A few fixes are also
invoked, using the mechanism described in the next section. Various
counters are also initialized before the run begins. The
``setup_minimal()`` method is a variant that has a flag for performing
less setup. This is used when runs are continued and information
from the previous run is still valid. For example, if repeated
short LAMMPS runs are being invoked, interleaved by other commands,
via the *pre no* and *every* options of the run command, the
``setup_minimal()`` method is used.
- The ``force_clear()`` method initializes force and other arrays to
zero before each timestep, so that forces (torques, etc) can be
accumulated.
Now for the ``Verlet::run()`` method. Its basic structure in hi-level pseudo
code is shown below. In the actual code in ``src/verlet.cpp`` some of
these operations are conditionally invoked.
.. code-block:: python
loop over N timesteps:
if timeout condition: break
ev_set()
fix->initial_integrate()
fix->post_integrate()
nflag = neighbor->decide()
if nflag:
fix->pre_exchange()
domain->pbc()
domain->reset_box()
comm->setup()
neighbor->setup_bins()
comm->exchange()
comm->borders()
fix->pre_neighbor()
neighbor->build()
fix->post_neighbor()
else:
comm->forward_comm()
force_clear()
fix->pre_force()
pair->compute()
bond->compute()
angle->compute()
dihedral->compute()
improper->compute()
kspace->compute()
fix->pre_reverse()
comm->reverse_comm()
fix->post_force()
fix->final_integrate()
fix->end_of_step()
if any output on this step:
output->write()
# after loop
fix->post_run()
The ``ev_set()`` method (in the parent Integrate class), sets two flags
(*eflag* and *vflag*) for energy and virial computation. Each flag
encodes whether global and/or per-atom energy and virial should be
calculated on this timestep, because some fix or variable or output will
need it. These flags are passed to the various methods that compute
particle interactions, so that they either compute and tally the
corresponding data or can skip the extra calculations if the energy and
virial are not needed. See the comments for the ``Integrate::ev_set()``
method which document the flag values.
At various points of the timestep, fixes are invoked,
e.g. ``fix->initial_integrate()``. In the code, this is actually done
via the Modify class which stores all the Fix objects and lists of which
should be invoked at what point in the timestep. Fixes are the LAMMPS
mechanism for tailoring the operations of a timestep for a particular
simulation. As described elsewhere, each fix has one or more methods,
each of which is invoked at a specific stage of the timestep, as show in
the timestep pseudo-code. All the active fixes defined in an input
script, that are flagged to have an ``initial_integrate()`` method are
invoked at the beginning of each timestep. Examples are :doc:`fix nve
<fix_nve>` or :doc:`fix nvt or fix npt <fix_nh>` which perform the
start-of-timestep velocity-Verlet integration operations to update
velocities by a half-step, and coordinates by a full step. The
``post_integrate()`` method is next for operations that need to happen
immediately after those updates. Only a few fixes use this, e.g. to
reflect particles off box boundaries in the :doc:`FixWallReflect class
<fix_wall_reflect>`.
The ``decide()`` method in the Neighbor class determines whether
neighbor lists need to be rebuilt on the current timestep (conditions
can be changed using the :doc:`neigh_modify every/delay/check
<neigh_modify>` command. If not, coordinates of ghost atoms are
acquired by each processor via the ``forward_comm()`` method of the Comm
class. If neighbor lists need to be built, several operations within
the inner if clause of the pseudo-code are first invoked. The
``pre_exchange()`` method of any defined fixes is invoked first.
Typically this inserts or deletes particles from the system.
Periodic boundary conditions are then applied by the Domain class via
its ``pbc()`` method to remap particles that have moved outside the
simulation box back into the box. Note that this is not done every
timestep, but only when neighbor lists are rebuilt. This is so that
each processor's sub-domain will have consistent (nearby) atom
coordinates for its owned and ghost atoms. It is also why dumped atom
coordinates may be slightly outside the simulation box if not dumped
on a step where the neighbor lists are rebuilt.
The box boundaries are then reset (if needed) via the ``reset_box()``
method of the Domain class, e.g. if box boundaries are shrink-wrapped to
current particle coordinates. A change in the box size or shape
requires internal information for communicating ghost atoms (Comm class)
and neighbor list bins (Neighbor class) be updated. The ``setup()``
method of the Comm class and ``setup_bins()`` method of the Neighbor
class perform the update.
The code is now ready to migrate atoms that have left a processor's
geometric sub-domain to new processors. The ``exchange()`` method of
the Comm class performs this operation. The ``borders()`` method of the
Comm class then identifies ghost atoms surrounding each processor's
sub-domain and communicates ghost atom information to neighboring
processors. It does this by looping over all the atoms owned by a
processor to make lists of those to send to each neighbor processor. On
subsequent timesteps, the lists are used by the ``Comm::forward_comm()``
method.
Fixes with a ``pre_neighbor()`` method are then called. These typically
re-build some data structure stored by the fix that depends on the
current atoms owned by each processor.
Now that each processor has a current list of its owned and ghost
atoms, LAMMPS is ready to rebuild neighbor lists via the ``build()``
method of the Neighbor class. This is typically done by binning all
owned and ghost atoms, and scanning a stencil of bins around each
owned atom's bin to make a Verlet list of neighboring atoms within the
force cutoff plus neighbor skin distance.
In the next portion of the timestep, all interaction forces between
particles are computed, after zeroing the per-atom force vector via the
``force_clear()`` method. If the newton flag is set to *on* by the
newton command, forces are added to both owned and ghost atoms, otherwise
only to owned (aka local) atoms.
Pairwise forces are calculated first, which enables the global virial
(if requested) to be calculated cheaply (at O(N) cost instead of O(N**2)
at the end of the ``Pair::compute()`` method), by a dot product of atom
coordinates and forces. By including owned and ghost atoms in the dot
product, the effect of periodic boundary conditions is correctly
accounted for. Molecular topology interactions (bonds, angles,
dihedrals, impropers) are calculated next (if supported by the current
atom style). The final contribution is from long-range Coulombic
interactions, invoked by the KSpace class.
The ``pre_reverse()`` method in fixes is used for operations that have to
be done *before* the upcoming reverse communication (e.g. to perform
additional data transfers or reductions for data computed during the
force computation and stored with ghost atoms).
If the newton flag is on, forces on ghost atoms are communicated and
summed back to their corresponding owned atoms. The ``reverse_comm()``
method of the Comm class performs this operation, which is essentially
the inverse operation of sending copies of owned atom coordinates to
other processor's ghost atoms.
At this point in the timestep, the total force on each (local) atom is
known. Additional force constraints (external forces, SHAKE, etc) are
applied by Fixes that have a ``post_force()`` method. The second half
of the velocity-Verlet integration, ``final_integrate()`` is then
performed (another half-step update of the velocities) via fixes like
nve, nvt, npt.
At the end of the timestep, fixes that contain an ``end_of_step()``
method are invoked. These typically perform a diagnostic calculation,
e.g. the ave/time and ave/spatial fixes. The final operation of the
timestep is to perform any requested output, via the ``write()`` method
of the Output class. There are 3 kinds of LAMMPS output: thermodynamic
output to the screen and log file, snapshots of atom data to a dump
file, and restart files. See the :doc:`thermo_style <thermo_style>`,
:doc:`dump <dump>`, and :doc:`restart <restart>` commands for more
details.
The the flow of control during energy minimization iterations is
similar to that of a molecular dynamics timestep. Forces are computed,
neighbor lists are built as needed, atoms migrate to new processors, and
atom coordinates and forces are communicated to neighboring processors.
The only difference is what Fix class operations are invoked when. Only
a subset of LAMMPS fixes are useful during energy minimization, as
explained in their individual doc pages. The relevant Fix class methods
are ``min_pre_exchange()``, ``min_pre_force()``, and ``min_post_force()``.
Each fix is invoked at the appropriate place within the minimization
iteration. For example, the ``min_post_force()`` method is analogous to
the ``post_force()`` method for dynamics; it is used to alter or constrain
forces on each atom, which affects the minimization procedure.
After all iterations are completed there is a ``cleanup`` step which
calls the ``post_run()`` method of fixes to perform operations only required
at the end of a calculations (like freeing temporary storage or creating
final outputs).
Modifying and extending LAMMPS
==============================
The :doc:`Modify` section of the manual gives an overview of how LAMMPS can
be extended by writing new classes that derive from existing
parent classes in LAMMPS. Here, some specific coding
details are provided for writing code for LAMMPS.
Writing a new fix style
^^^^^^^^^^^^^^^^^^^^^^^
Writing fixes is a flexible way of extending LAMMPS. Users can
implement many things using fixes:
- changing particles attributes (positions, velocities, forces, etc.). Examples: FixNVE, FixFreeze.
- reading/writing data. Example: FixRestart.
- adding or modifying properties due to geometry. Example: FixWall.
- interacting with other subsystems or external code: Examples: FixTTM, FixExternal, FixLATTE
- saving information for analysis or future use (previous positions,
for instance). Examples: Fix AveTime, FixStoreState.
All fixes are derived from the Fix base class and must have a
constructor with the signature: ``FixPrintVel(class LAMMPS *, int, char **)``.
Every fix must be registered in LAMMPS by writing the following lines
of code in the header before include guards:
.. code-block:: c
#ifdef FIX_CLASS
FixStyle(print/vel,FixPrintVel)
#else
/* the definition of the FixPrintVel class comes here */
...
#endif
Where ``print/vel`` is the style name of your fix in the input script and
``FixPrintVel`` is the name of the class. The header file would be called
``fix_print_vel.h`` and the implementation file ``fix_print_vel.cpp``.
These conventions allow LAMMPS to automatically integrate it into the
executable when compiling and associate your new fix class with the designated
keyword when it parses the input script.
Let's write a simple fix which will print the average velocity at the end
of each timestep. First of all, implement a constructor:
.. code-block:: C++
FixPrintVel::FixPrintVel(LAMMPS *lmp, int narg, char **arg)
: Fix(lmp, narg, arg)
{
if (narg < 4)
error->all(FLERR,"Illegal fix print/vel command");
nevery = force->inumeric(FLERR,arg[3]);
if (nevery <= 0)
error->all(FLERR,"Illegal fix print/vel command");
}
In the constructor you should parse your fix arguments which are
specified in the script. All fixes have pretty the same syntax:
``fix <fix-ID> <fix group> <fix name> <fix arguments ...>``. The
first 3 parameters are parsed by Fix base class constructor, while
``<fix arguments>`` should be parsed by you. In our case, we need to
specify how often we want to print an average velocity. For instance,
once in 50 timesteps: ``fix 1 print/vel 50``. There is a special variable
in the Fix class called ``nevery`` which specifies how often the method
``end_of_step()`` is called. Thus all we need to do is just set it up.
The next method we need to implement is ``setmask()``:
.. code-block:: C++
int FixPrintVel::setmask()
{
int mask = 0;
mask |= FixConst::END_OF_STEP;
return mask;
}
Here the user specifies which methods of your fix should be called
during execution. The constant ``END_OF_STEP`` corresponds to the
``end_of_step()`` method. The most important available methods that
are called during a timestep and the order in which they are called
are shown in the previous section.
.. code-block:: C++
void FixPrintVel::end_of_step()
{
// for add3, scale3
using namespace MathExtra;
double** v = atom->v;
int nlocal = atom->nlocal;
double localAvgVel[4]; // 4th element for particles count
memset(localAvgVel, 0, 4 * sizeof(double));
for (int particleInd = 0; particleInd < nlocal; ++particleInd) {
add3(localAvgVel, v[particleInd], localAvgVel);
}
localAvgVel[3] = nlocal;
double globalAvgVel[4];
memset(globalAvgVel, 0, 4 * sizeof(double));
MPI_Allreduce(localAvgVel, globalAvgVel, 4, MPI_DOUBLE, MPI_SUM, world);
scale3(1.0 / globalAvgVel[3], globalAvgVel);
if ((comm->me == 0) && screen) {
fmt::print(screen,"{}, {}, {}\n",
globalAvgVel[0], globalAvgVel[1], globalAvgVel[2]);
}
}
In the code above, we use MathExtra routines defined in
``math_extra.h``. There are bunch of math functions to work with
arrays of doubles as with math vectors. It is also important to note
that LAMMPS code should always assume to be run in parallel and that
atom data is thus distributed across the MPI ranks. Thus you can
only process data from local atoms directly and need to use MPI library
calls to combine or exchange data. For serial execution, LAMMPS
comes bundled with the MPI STUBS library that contains the MPI library
function calls in dummy versions that only work for a single MPI rank.
In this code we use an instance of Atom class. This object is stored
in the Pointers class (see ``pointers.h``) which is the base class of
the Fix base class. This object contains references to various class
instances (the original instances are created and held by the LAMMPS
class) with all global information about the simulation system.
Data from the Pointers class is available to all classes inherited from
it using protected inheritance. Hence when you write you own class,
which is going to use LAMMPS data, don't forget to inherit from Pointers
or pass an Pointer to it to all functions that need access. When writing
fixes we inherit from class Fix which is inherited from Pointers so
there is no need to inherit from it directly.
The code above computes average velocity for all particles in the
simulation. Yet you have one unused parameter in fix call from the
script: ``group_name``. This parameter specifies the group of atoms
used in the fix. So we should compute average for all particles in the
simulation only if ``group_name == "all"``, but it can be any group.
The group membership information of an atom is contained in the *mask*
property of and atom and the bit corresponding to a given group is
stored in the groupbit variable which is defined in Fix base class:
.. code-block:: C++
for (int i = 0; i < nlocal; ++i) {
if (atom->mask[i] & groupbit) {
// Do all job here
}
}
Class Atom encapsulates atoms positions, velocities, forces, etc. User
can access them using particle index. Note, that particle indexes are
usually changed every few timesteps because of neighbor list rebuilds
and spatial sorting (to improve cache efficiency).
Let us consider another Fix example: We want to have a fix which stores
atoms position from previous time step in your fix. The local atoms
indexes may not be valid on the next iteration. In order to handle
this situation there are several methods which should be implemented:
- ``double memory_usage()``: return how much memory the fix uses (optional)
- ``void grow_arrays(int)``: do reallocation of the per particle arrays in your fix
- ``void copy_arrays(int i, int j, int delflag)``: copy i-th per-particle
information to j-th. Used when atom sorting is performed. if delflag is set
and atom j owns a body, move the body information to atom i.
- ``void set_arrays(int i)``: sets i-th particle related information to zero
Note, that if your class implements these methods, it must call add calls of
add_callback and delete_callback to constructor and destructor. Since we want
to store positions of atoms from previous timestep, we need to add
``double** xold`` to the header file. Than add allocation code
to the constructor:
.. code-block:: C++
FixSavePos::FixSavePos(LAMMPS *lmp, int narg, char **arg), xold(nullptr)
{
//...
memory->create(xold, atom->nmax, 3, "FixSavePos:x");
atom->add_callback(0);
}
FixSavePos::~FixSavePos() {
atom->delete_callback(id, 0);
memory->destroy(xold);
}
Implement the aforementioned methods:
.. code-block:: C++
double FixSavePos::memory_usage()
{
int nmax = atom->nmax;
double bytes = 0.0;
bytes += nmax * 3 * sizeof(double);
return bytes;
}
void FixSavePos::grow_arrays(int nmax)
{
memory->grow(xold, nmax, 3, "FixSavePos:xold");
}
void FixSavePos::copy_arrays(int i, int j, int delflag)
{
memcpy(xold[j], xold[i], sizeof(double) * 3);
}
void FixSavePos::set_arrays(int i)
{
memset(xold[i], 0, sizeof(double) * 3);
}
int FixSavePos::pack_exchange(int i, double *buf)
{
int m = 0;
buf[m++] = xold[i][0];
buf[m++] = xold[i][1];
buf[m++] = xold[i][2];
return m;
}
int FixSavePos::unpack_exchange(int nlocal, double *buf)
{
int m = 0;
xold[nlocal][0] = buf[m++];
xold[nlocal][1] = buf[m++];
xold[nlocal][2] = buf[m++];
return m;
}
Now, a little bit about memory allocation. We use the Memory class which
is just a bunch of template functions for allocating 1D and 2D
arrays. So you need to add include ``memory.h`` to have access to them.
Finally, if you need to write/read some global information used in
your fix to the restart file, you might do it by setting flag
``restart_global = 1`` in the constructor and implementing methods void
``write_restart(FILE *fp)`` and ``void restart(char *buf)``.
If, in addition, you want to write the per-atom property to restart
files additional settings and functions are needed:
- a fix flag indicating this needs to be set ``restart_peratom = 1;``
- ``atom->add_callback()`` and ``atom->delete_callback()`` must be called
a second time with the final argument set to 1 instead of 0 (indicating
restart processing instead of per-atom data memory management).
- the functions ``void pack_restart(int i, double *buf)`` and
``void unpack_restart(int nlocal, int nth)`` need to be implemented

View File

@ -586,6 +586,7 @@ del
delaystep
DeleteIDs
deleteIDs
delflag
Dellago
delocalization
delocalized
@ -1104,6 +1105,7 @@ gromos
Gronbech
Groot
groupbig
groupbit
grp
Grueneisen
gsmooth

3
src/.gitignore vendored
View File

@ -32,6 +32,9 @@
/pair_kim.cpp
/pair_kim.h
/superpose3d.h
/math_eigen.h
/kokkos.cpp
/kokkos.h
/kokkos_type.h